学习009---面向对象oop
oop
以类的方式组织代码,以对象的组织(封装)数据
注:本系列学习自狂神说(Java):
当前的目标是建造自己的网页!
俺的博客:startsmaple
目录
面向过程

回顾

方法的定义
修饰符 返回值类型 方法名(参数){
方法体;
return 返回值;
}
方法的调用
//实例化这个类 new
//对象类型 对象名 = 对象值;
Student student = new Student();
student.say();
类
class Person{
String name;
}
引用传递本质还是值传递
package com.oop.demo01;
public class Demo05 {
//值传递
public static void main(String[] args) {
int a = 1;
System.out.println(a);//1
Demo05.change(a);
System.out.println(a);//1
}
public static void change(int a){
a = 10;
}
}
out:
1
1
package com.oop.demo01;
public class Demo06 {
//引用传递
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
Demo06.change(person);
System.out.println(person.name);
//此处的person是一个对象,指向的是类里面的name
}
public static void change(Person person){
person.name = "??????????????????????";
}
}
class Person{
String name;
}
out:
null
???????????????????????
解析
本质是创建了一个引用对象person,person指向的还是Person person = new Person();
是一个具体的人,可以改变里面属性
构造器
语法
先创建一个类
package com.oop.demo02;
public class Person {
}
打开class文件,发现一个类如果什么都不写。class文件会自动生成一个方法
idea打开class文件
package com.oop.demo02;
public class Person {
public Person() {
}
}
此处的Person(){}即构造器(构造方法)
特点:
- 必须和类名返回值相同
- 必须没有返回类型,也不能写void
package com.oop.demo02;
public class Person {
//属性
String name;
//作用是用来实例化、初始化值
//1. 使用new关键字,本质是在调用构造器
//Person person = new Person();
//无参构造
public Person(){
this.name = "abc";
}
//2.有参构造,无参构造就必须显示定义
//也就是说,如果你什么都不写,系统自动生成无参构造
//但是你写了有参构造,系统就不帮你写了,你要自己写
public Person(String name) {
this.name = name;
}
//3.快捷键alt + insert 生成构造器
}
package com.oop.demo02;
//学生类
public class Student {
//属性
String name;
//初始化默认0 0.0
//char u0000
//boolen 0(false)
//引用 null
int age;
//方法
public void study(){
System.out.println("学生在学习");
}
}
package com.oop.demo02;
//规范:一个项目应该只存在一个main
public class Application {
public static void main(String[] args) {
//类:是抽象的,实例化
Person person = new Person();
Person person2 = new Person("starsmaple");
Student student = new Student();
student.study();
}
}
图解构造


方法区是特殊的堆
用idea打开class文件
打开项目结构


添加out目录,在out目录下寻找对应文件即可
三大特性
1. 封装
理解
即:该露的露,该藏的藏
-
高内聚,低耦合
- 高内聚:类的内部数据操作自己完成,不允许外部干涉
- 低耦合:只暴露少量的方法给外部使用
-
封装即隐藏
-
属性私有,get/set【只要记住这句话】
模板
package com.oop.demo04;
public class Student {
//属性私有
private String name;
private int id;
private char sex;
private int age;
//提供一些public来操作属性
//get set
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
//快捷键 alt + insert
//get set的作用
//规避不合法
//1.提高程序安全性,保护数据
//2.隐藏代码细节
//3.统一接口
//4.系统可维护性增加了
public int getAge() {
return age;
}
public void setAge(int age) {
if(age>=0&&age<=120)
this.age = age;
else {
System.out.println("The age if illegal");
this.age = -1;
}
}
}
package com.oop.demo04;
public class Application {
public static void main(String[] args) {
//Demo01
// Student xiaoming = new Student();
// Student xiaohong = new Student();
//
// xiaohong.name = "小明";
// xiaoming.age = 3;
//
// System.out.println(xiaohong.name);
// System.out.println(xiaohong.age);
//
//
//
//
// Demo02
System.out.println("Demo02======================");
Student student01 = new Student();
student01.setAge(999);
System.out.println(student01.getAge());;
}
}
get set的作用
//规避不合法
//1.提高程序安全性,保护数据
//2.隐藏代码细节
//3.统一接口
//4.系统可维护性增加了
2. 继承
本质是对类再次抽象
extends拓展,子类是父类的拓展
java中只有单继承
引入
继承
先创建
package com.oop.demo05;
//父类,基类
public class Person {
protected String name = "Father:Person";
public int money = 10_0000_0000;
public Person() {
System.out.println("Person无参构造");
}
public test(String str){
System.out.println(str);
}
}
package com.oop.demo05;
//子类(派生类,
public class Student extends Person{
}
package com.oop.demo05;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test("main");//使用父亲的方法
student.money -= 10000;//儿子花掉了父亲的钱
}
创建了子类,却能使用父类的test,即继承
组合
package com.oop.demo05;
//组合
public class Teather {
Person person;
}
等级
public > protected > default > private
如果父类属性私有,则子类无法访问
一般来说属性都为私有,而留有接口get()set()来让人修改
Object类
每个类都会直接或间接继承object类。
package com.oop.demo05;
public class Person extends Object{
}
其中extends Object 没有必要写
super()
每个子类都会在第一行出现super();调用父类的无参构造(隐藏代码,默认自动添加
所以如果父类没有无参构造,子类要自己写super有参构造
如果super(); 上面有东西 会报错
******同样的,this();构造器也要放在第一行
package com.oop.demo05;
//子类(派生类,
public class Student extends Person{
super();//可写可不写
//继承时,自动会在最上方添加super();
//相当于构建了一个父类
//父类必须要有无参构造,否则只能调用父类的有参
private String naem = "Student";
//在此处就不能写super();必须写在子类第一行
public void test(String name){
System.out.println(name);
System.out.println(this.naem);
System.out.println(super.name);//访问父类的属性(public)
}
public Student() {
System.out.println("Student 无参构造");
}
}
注意点:
super注意点:
1.super调用父类的构造方法,必须在构造方法的最上面(第一个
2.super只能出现在子类或构造方法中
3.super和this不能同时调用构造方法
super Vs this
1.代表对象不同
2.前提:
this没有继承也能用
3.构造方法:
this调用本类的构造
super调用父类的构造
重写
子类重写父类的方法
不能重写的:
static
final 常量
private
重写只能是public
package com.oop.demo05;
public class A extends B {
@Override//注解,有功能的注解!!
public void test() {
System.out.println("A=>test()");
}
}
package com.oop.demo05;
//重写都是方法的重写和属性无关
public class B {
public void test(){
System.out.println("B=>test()");
}
}
package com.oop.demo05;
public class Application {
public static void main(String[] args) {
//方法的调用只和左边,定义的数据类型有关
A a = new A();
a.test();
//父类的引用指向了子类
B b = new A();//子类重写父类的方法
//重写只能是public
b.test();
}
}
//out
//A=>test()
//A=>test()
快捷键alt+insert


箭头所指o是指override重写
小结note
重写:
1.方法名要相同
2.参数列表必须相同
3.修饰符:范围可以扩大public》protected》default》private
4.抛出的异常:可以缩小但不能扩大:ClassNotFoundEcpection --> Expection(big)
重写:子类的方法和父类要一致。方法体不同
为什么要重写:
1.父类的功能子类不一定需要,或者不需要满足(太少
Alt + Insert : override;
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
用法
Father f1 = new Son();
所有的内容是和new 后面的Student()一致的
有什么样的函数是取决于前面的 Student,Person,Object
以及父类的public函数
相当于把前面Person 里面有的 方法 按Student的模板重写了一遍
不能重写的:
static
final 常量
private
测试
注解A的函数test------变成了继承
package com.oop.demo05;
public class Application {
public static void main(String[] args) {
A a = new A();
a.test();
//父类的引用指向了子类
B b = new A();//子类重写父类的方法
//重写只能是public
b.test();
}
}
---------------------------------
package com.oop.demo05;
public class A extends B {
// @Override//注解,有功能的注解!!
// public void test() {
// System.out.println("A=>test()");
// }
}
----------------------------------
package com.oop.demo05;
public class B {
public void test(){
System.out.println("B=>test()");
}
}
out:
B=>test()
B=>test()
注解B的函数test------变成了继承
---------------------------------
package com.oop.demo05;
public class A extends B {
@Override//注解,有功能的注解!!
public void test() {
System.out.println("A=>test()");
}
}
----------------------------------
package com.oop.demo05;
public class B {
// public void test(){
// System.out.println("B=>test()");
// }
}
out:
错误:找不到b的test
让方法变成static
---------------------------------
package com.oop.demo05;
public class A extends B {
@Override//注解,有功能的注解!!
public static void test() {
System.out.println("A=>test()");
}
}
----------------------------------
package com.oop.demo05;
public class B {
public static void test(){
System.out.println("B=>test()");
}
}
out:
A=>test()
B=>test()
3. 多态
一个对象的实际类型是确定的-------------所有的内容是和new 后面的Student()一致的
new Person();
new Student();
可以指向的引用类型就不确定了,父类的引用指向子类--------------有什么样的函数是取决于前面的 Student,Person,Object
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
称为多态
package com.oop.demo06;
public class Student extends Person{
public void eat(){
sout("eat");
}
public void go(){
System.out.println("go");
}
}
-----------------------------------
package com.oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
public void go(){
sout("????????????????")
}
}
------------------------------------
package com.oop.demo06;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public abstract class Application {
public static void main(String[] args) {
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
s1.run();//run
s2.run();//run
s1.go();//go
s2.go();//go
s1.eat();//eat
s2.eat();//错误
}
}
解析:
继承:父类有,子类继承父类函数
s1.run();//run
s2.run();//run
重写:子类重写父类函数,父类的引用指向子类,故父类中的对应函数被子类覆盖
s1.go();//go
s2.go();//go
子类有,父类没有,报错:找不到父类的引用
s1.eat();//eat
s2.eat();//错误//不能调用子类独有的方法
也就是说,对象能执行哪些方法,主要看左边的类型
错误解决方法------强制转化(高转低)
((Student)s2).eat();
注意事项:
-
多态是方法的多态,属性没有多态
-
父类和子类,有联系
-
类型转化异常:ClassCastException
-
存在条件:继承关系,方法需要重写
-
看前面的类型,是否为父类=子类,是否子类父类都有
模板:Father f1 = new Son();
- 父类有:走父类
- 都有:重写,走子类
- 子类有:不应存在
-
多态中不会出现的修饰符
- static 是属于类的,不属于实例,和类相关
- final 常量无法改变
- private 私有方法无法被重写
instansof 和 类型转化
instanceof判断两个类型之间是否有关系
instanceof(实体)
insanceof
package com.oop.demo06;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public abstract class Application {
public static void main(String[] args) {
//instanceof
//判断类型是否相似
//模板:sout(X instanceof Y);
//结果
//1. 编译通过:是否存在父子关系,X能否转化为Y
//2. 1/0:X的实际类型student是否是Student本身,子类或间接子类
Object object = new Student();
//Object > String
//Object > Person > Teather
//Object > Person > Student
System.out.println(object instanceof Student);1
System.out.println(object instanceof Person);1
System.out.println(object instanceof Object);1
System.out.println(object instanceof Teacher);0
System.out.println(object instanceof String);0
Person person = new Student();
System.out.println(person instanceof Student);
System.out.println(person instanceof Person);
System.out.println(person instanceof Object);
System.out.println(person instanceof Teacher);
//System.out.println(person instanceof String);编译错误,相同等级下不能比较
Student student = new Student();
System.out.println(student instanceof Student);
System.out.println(student instanceof Person);
System.out.println(student instanceof Object);
//System.out.println(student instanceof Teacher);编译错误
//System.out.println(student instanceof String);编译错误
}
}
解释
boolean result = obj ``instanceof Class
其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。
注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。
类型转化
package com.oop.demo06;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public abstract class Application {
public static void main(String[] args) {
//强制转化P13,高转低,强制转化为子类,向下转型
//高 低
Person obj = new Student();
//obj.eat();报错
Student student = (Student) obj;//强制转换
student.eat();
//以上两行可以直接((Student)obj).eat();
//******(Student)obj.eat()是直接对函数obj.eat()进行强制转化,需要((Student)obj).eat();才能
//低转高:子类自动转化为父类,可能会丢失本来的一些方法,向上转型
Person person = student;
//person.eat();//报错找不到eat()
}
}
static关键词
静态属性
package com.oop.demo07;
//static
public class Student {
private static int age;
private double score;
public static void main(String[] args) {
Student s1= new Student();
System.out.println(Student.age);//对于静态变量,我们推荐使用类.变量
//System.out.println(Student.score);无法访问
System.out.println(s1.score);
System.out.println(s1.age);
}
}
如果一个属性是静态的那么可以直接用Student.age访问,并且推荐使用类名访问
会在多线程里面用到
静态方法
package com.oop.demo07;
//static
public class Student {
public void run(){
go();
}
public static void go(){
}
public static void main(String[] args) {
new Student().run();
Student.go();
}
}
非静态方法可以调用静态方法
静态方法可以调用静态方法,但不能调用非静态
代码块
package com.oop.demo07;
public class /*fianl*/ Person {
{
System.out.println("匿名代码块");//代码块(匿名代码块
}
static {
System.out.println("静态代码块");//静态代码块
}
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("============");
Person person2 = new Person();
//静态只生成一次
}
}
out:
静态代码块
匿名代码块
构造方法
===========
匿名代码块
构造方法
以上main()方法测试说明静态代码块只执行一次
不推荐使用匿名代码块,匿名代码块一般用来附初值
但在加载某些初始化数据的时候,会使用静态代码块
import
调用类里面函数
有时候在调用其他类里的函数时总是要写Math.random();
避免老是重复写Math,在最开头加
import static java.lang.Math.random;
称为静态导入包
通配符*
import static java.lang.Math.*;表示导入math里的所有函数
package com.oop.demo07;
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());
System.out.println(random());//在有静态导入包之后可以不用写Math
System.out.println(PI);
}
}
final常量
final之后,断子绝孙
package com.oop.demo07;
public class fianl Person {
}
-----------------------------------------------------
package com.oop.demo07;
//static
public class Student extends Person 不能继承final常量{
}
报错:无法继承final常量
抽象类
加了abstract就是抽象类
相当于抽象类写了用来约束的框架,然后由子类来帮我们实现框架的具体内容
不能new抽象类
子类必须实现父类的所有抽象函数
package com.oop.demo08;
public abstract class Action {
//约束,自己只想写框架,下面的内容希望有人帮我们写(实现
//只有方法的声明,没有实现
public abstract void dpSomething();
//1. 不能new抽象类
//2. 抽象类中可以写普通方法
//3. 抽象方法必须在抽象类中
//抽象的抽象
}
package com.oop.demo08;
public class A extends Action {
//抽象类的所有方法必须有继承他的子类,都要实现他的方法
//除非子类也是抽象类,要子子类
@Override
public void dpSomething() {
}
}
抽象类中可以写普通方法
package com.oop.demo08;
public abstract class Action {
public void hello(){
}
}
抽象类的意义:1提高开发效率,2进行约束,比如游戏,每创建一个角色只要继承这个抽象类,重写他的方法就行了。
抽象类存在构造器
接口
-
普通类:只有具体实现
-
抽象类:具体实现和规范(抽象方法)都有
-
接口:只有规范,没有方法
-
接口作用:实现约束和实现分离(进公司后,一般是面向接口编程,即写里面的方法
是oop的精髓,是对对象的抽象
接口的本质是契约:即“如果你是……,那么你必须会……”
关键字interface
package com.oop.demo09;
public interface TimeService {
void timer();
}
接口中的函数都是public abstract 修饰的
**接口中的属性都是public static final **,不过一般不会在接口里放常量
在idea中标灰,说明默认添加可以不写

应用
package com.oop.demo09;
//接口
public interface UserService {
public static final int age = 99;//是个常量
//不过一般没有人会在接口里面定义常量
public void add(String name);
public void delete(String name);
public void query(String name);
public void update(String name);
}
- 接口都需要有实现
- 接口可以重写多个
package com.oop.demo09;
//抽象类 extends
//类 可以实现接口 implements
//实现了接口的类,就要重写接口的方法
//接口可以重写多个!利用接口进行多继承
//不过 抽象类里可以有方法的实现,但是接口只有方法的定义
public abstract class UserServiceImpl implements UserService,TimeService{
@Override
public void run() {
}
@Override
public void run(String name) {
}
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void query(String name) {
}
@Override
public void update(String name) {
}
}
接口的作用:
1.约束
2.定义一些方法,让不同的人来实现
3.public abstract
4.public static final
5.接口不能被实例化,接口中没有构造方法
6.implements 可以实现多个接口
7.必须重写接口中所有方法
8.总结博客
内部类
A类中定义B类,那么B类相对A而言是内部类
- 可以获得外部类的私有属性
package com.oop.demo10;
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类的方法");
}
public class Inner{
System.out.println("这是内部类的方法");
}
//获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
package com.oop.demo10;
public class Application {
//new
public static void main(String[] args) {
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.in();
//匿名对象的使用,不用将实例保存到变量中
new Outer().out();
}
}
关于静态
注意!如果该内部类类静态,public static Inner{}
,则不能获得外部类的私有属性,因为static先生成,而此时 外部id还没有出生
解决方法:把id 也改成static
package com.oop.demo10;
public class Outer {
private int id;
public class static Inner{
}
public void getID(){
System.out.println(id);//报错
}
}
}
可以有多个类
一个java只能有一个public class,但是可以有多个class,也可以有接口
相当于在大的java文件里面写了两个不同的类
也可以在方法里面定义类--局部内部类
package com.oop.demo10;
public class Outer {
public void eat(){sout("I eat an apple")}
public class Inner{};
}
//局部内部类
public void method(){
class Inner{
public void in(){}
}
}
}
//一个java类里只能有一个public
//但是可以有多个类
class A{
psvm//可以在里面写main()方法,所以可以当成测试类
}
interface UserService{
void hello();
}
匿名使用
package com.oop.demo10;
public class Application {
//new
public static void main(String[] args) {
//匿名对象的使用,不用将实例保存到变量中
new Outer().out();
//匿名接口
new UserService() {
//重写
@Override
public void hello() {
}
};
//接口也有返回值
UserService userService = new UserService() {
@Override
public void hello() {
}
};
}
}

浙公网安备 33010602011771号