【Java基础07】面向对象进阶
文章目录
- 面向对象进阶
- 1.static
- 1.1 static的概念和特点以及调用方式
- static内存图(这部分没看)
- 1.2 静态成员方法
- 1.3 工具类
- 练习:定义数组工具类
- 1.4 static的注意事项
- 2. 继承
- 2.1 继承的概念和优点
- 2.2 继承的特点
- 2.3 子类到底能继承父类中的哪些内容? (内存图/内存分析工具)内存部分没细看需要重新学习
- 2.3.1 构造方法
- 2.3.2 成员变量
- 2.3.3 成员方法
- 2.4 继承中:成员变量的访问特点
- 2.5 继承中:成员方法的访问特点
- 方法的重写
- 2.6 继承中:构造方法的访问特点
- 2.7 this和super使用总结
- 综合练习
- 3.多态
- 3.1 什么是多态及多态的应用场景
- 3.2 多态调用成员的特点(内存图部分没看)
- 3.3 多态的优势和弊端
- 3.3.1 多态的优势
- 关于StringBuilder和ArrayList的补充
- 3.3.2 多态的弊端以及解决办法
- 3.4 多态综合练习
- 4.包、final、权限修饰符、代码块
- 4.1 包
- 4.2 final
- 4.2.1 final修饰方法
- 4.2.2 final修饰类
- 4.2.3 final修饰变量(常量)
- 4.2.4 关于常量(学了内存相关的内容可以再来理解一下这里)
- final修饰基本类型
- final修饰引用类型
- 4.3 权限修饰符
- 4.4 代码块
- 构造代码块
- 静态代码块(重点)
- 5.抽象类
- 6.接口
- 6.1 接口的定义和使用
- 6.2 接口和类之间的关系
- 6.1.1 接口多学三招
- 6.1.2 接口的应用
- 6.1.2 适配器设计模式
- 7.内部类
- 7.1 内部类的概念
- 7.2 内部类的分类
- 成员内部类(用得少,内存图没有看)
- 静态内部类和局部内部类(用得少)
- 匿名内部类(用得多)
- 作为类的子类对象和接口的实现类对象,存在多态的用法。方法的参数是接口或者类的时候,可以直接在调用的时候写一次匿名内部类,这样不需要额外写一个类文件,并且通过多态机制,这个新写的类可以直接作为参数传入。
本文部分参考这篇文章
面向对象进阶
1.static
1.1 static的概念和特点以及调用方式
package a01staticdemo1;public class Student {private String name;private String gender;private int age;//public String teacherName; 这样的话,老师是每一个对象的属性,每个学生想要输出老师的话,需要各自赋值public static String teacherName; //加上static之后,Student类所有的对象都共享同一个老师的值public Student() {}public Student(int age, String gender, String name) {this.age = age;this.gender = gender;this.name = name;}public String getName() {return name;}public String getGender() {return gender;}public int getAge() {return age;}public void setName(String name) {this.name = name;}public void setGender(String gender) {this.gender = gender;}public void setAge(int age) {this.age = age;}public void study() {System.out.println(name + "正在学习");}public void show(){System.out.println(name + "," + gender + "," + age + "," + teacherName);}}
package a01staticdemo1;public class StudentTest {public static void main(String[] args) {//创建第一个学生对象Student s1 = new Student();s1.setName("zhangsan");s1.setAge(23);s1.setGender("男");s1.teacherName = "a老师";//也完全可以像以下这种方式调用,推荐这种方式Student.teacherName = "a老师";s1.study();s1.show();//创建第二个学生对象Student s2 = new Student();s2.setName("lisi");s2.setAge(24);s2.setGender("男");s2.study();s2.show();}
}
static表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量。
static内存图(这部分没看)
1.2 静态成员方法
注意:static修饰的成员变量、方法,都推荐使用类名调用!
1.3 工具类
创建一个工具类的对象没有意义,所以构造方法要私有化
练习:定义数组工具类
ArrayUtil.java
package a02staticdemo2;import java.util.StringJoiner;public class ArrayUtil {//私有化构造方法//目的:为了不让外界创建它的对象private ArrayUtil() {}//工具方法//需要定义为静态的,方便调用public static String printArr(int[] arr){StringJoiner sj = new StringJoiner(",","[","]");for (int i = 0; i < arr.length; i++) {sj.add(String.valueOf(arr[i])); //point sj需要传入字符串,不像stringbuilder可以传入int}return sj.toString();}public static double getAverage(double[] arr){double sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}double avg = sum*1.0 / arr.length;return avg;//String.valueOf(...) 是 Java String 类的一个静态方法。//作用:把参数转换成字符串(String 对象)。}
}
TestDemo.java
package a02staticdemo2;public class TestDemo {public static void main(String[] args) {//测试工具类中的两个方法是否正确int[] arr1 = {1,2,3,4,5};String str = ArrayUtil.printArr(arr1);System.out.println(str);double[] arr2 = {1.0,2.0,3,4,5};double avg = ArrayUtil.getAverage(arr2);System.out.println(avg);}
}
1.4 static的注意事项
重新认识main方法
2. 继承
2.1 继承的概念和优点
什么时候用继承?
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码
子类可以得到父类的属性和行为,子类可以使用。
2.2 继承的特点
Java只支持单继承
不支持多继承
支持多层继承
一个案例:
Animal.java
package a01extendsdemo1;public class Animal {public void eat() {System.out.println("吃东西");}public void drink() {System.out.println("喝水");}
}
Cat.java
package a01extendsdemo1;public class Cat extends Animal {public void catchMouse(){System.out.println("猫抓老鼠");}
}
Dog.java
package a01extendsdemo1;public class Dog extends Animal {public void lookHome(){System.out.println("狗看家");
}
Lihua.java
package a01extendsdemo1;public class LiHua extends Cat{
}
Ragdoll.java
package a01extendsdemo1;public class Ragdoll extends Cat {
}
Husky.java
package a01extendsdemo1;public class Husky extends Dog{public void breakHome(){System.out.println("哈士奇在拆家");}
}
Teddy.java
package a01extendsdemo1;public class Teddy extends Dog{public void touch(){System.out.println("泰迪蹭");}
}
Test.java
package a01extendsdemo1;public class Test {public static void main(String[] args) {//1.创建布偶猫的对象Ragdoll rd = new Ragdoll();rd.eat();rd.drink();rd.catchMouse();System.out.println("-------------");//2.创建哈士奇的对象Husky h = new Husky();h.eat();h.drink();h.breakHome();}
}
子类只能访问父类中非私有的成员。如果要使用,可以用get和set方法
2.3 子类到底能继承父类中的哪些内容? (内存图/内存分析工具)内存部分没细看需要重新学习
2.3.1 构造方法
父类的构造方法不能被子类继承,因为会冲突。
违背了构造方法的原理,构造方法和子类的类名不一样了
2.3.2 成员变量
不管是否私有都可以继承,只是私有的子类不能直接使用。 如果要使用,需要get和set方法。
2.3.3 成员方法
不需要一层一层找,直接在虚方法表中就可以找到
2.4 继承中:成员变量的访问特点
就近原则
父类的非私有成员变量已经有赋值,如果子类不重新给自己的成员变量赋值,不使用this指明的话,会输出父类的值。毕竟会在构造前先调用一下父类的构造。
如上图,都没有找到的话会报错
关于变量重名的情况
有this,到本类的成员位置找
super表示父类
最多只能用一次super!!
一个案例:
2.5 继承中:成员方法的访问特点
通过子类对象访问一个方法,顺序如下:
子类成员范围找
父类成员范围找
如果都没用就报错(不考虑父亲的父亲…)
方法前都会有隐含的this,因为方法在调用的时候需要有调用者
package a02extendsdemo2;public class Test {public static void main(String[] args) {Student s = new Student();s.lunch();overseasStudent os = new overseasStudent();os.lunch();}
}class Person {public void eat(){System.out.println("吃米饭");}public void drink(){System.out.println("喝水");}
}class Student extends Person{public void lunch(){//现在本类中查看eat和drink方法,本类(子类)有就调用子类的,没有的话会调用从父类继承下来的eat和drinkeat();drink();this.eat();this.drink();//直接调用父类中的eat和drinksuper.eat();super.drink();}
}class overseasStudent extends Person {@Overridepublic void eat(){System.out.println("吃白人饭");}@Overridepublic void drink(){System.out.println("喝凉水");}public void lunch(){this.eat();this.drink();super.eat();super.drink();}
}
方法的重写
上面的代码有案例
方法重写的本质
第四点: 尽量是完全一致,就没有访问权限,名称,形参这些问题了
第三点:指的是父类方法如果返回值是Animal的话,子类是Animal或者Cat都可以。但父类方法是Cat的话,子类不可以是Animal。
第五点:非private,非final,非static的才能被添加到虚方法表中。
一个案例
画图从下往上,代码从上往下
可以直接用super.eat(),不需要额外再写一遍父类中的内容了,如下。
2.6 继承中:构造方法的访问特点
先调用一下父类的无参构造,父类必须得有东西,子类才能用。
package a03extendsdemo3;public class Person {String name;int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}
}
package a03extendsdemo3;public class Student extends Person {public Student(){super();System.out.println("子类的无参构造");}public Student(String name, int age) {//1.因为不是private,用this赋值也可以//this.name = name;//this.age = age;//2.用super调用父类的构造方法,即使是private也可以用super(name, age);}
}
package a03extendsdemo3;public class Test {public static void main(String[] args) {Student s = new Student("zs",23);System.out.println(s.name+"," +s.age);}
}
2.7 this和super使用总结
this可以理解为一个局部变量,表示当前方法调用者的地址!对象中是没有this的!
this代表所在类的对象引用。方法被哪个对象调用,this就代表哪个对象。
局部变量如果不和成员变量重名,访问成员变量的时候this.可以省略不写。
关于访问构造方法的部分:
this()表示调用本类其他构造方法。并且写了这句之后,虚拟机就不会再添加super()了。因为其他构造方法的第一行也会是默认的super()。
综合练习
package a04extendsdemo4;public class Employee {//1.类名见名知意//2.所有成员变量都要私有//3.构造方法至少两个(空参,全部参)//4.get/set方法//5.成员方法private String id;private String name;private double salary;public Employee() {}public Employee(String id, String name, double salary) {this.id = id;this.name = name;this.salary = salary;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public void work(){System.out.println("员工在工作");}public void eat(){System.out.println("员工在吃饭");}
}
package a04extendsdemo4;public class Cook extends Employee{public Cook() {}public Cook(String id, String name, double salary) {super(id, name, salary);}@Overridepublic void work() {System.out.println("炒菜");}
}
package a04extendsdemo4;public class Manager extends Employee{private double bonus;public Manager() {//自动生成的空参这里还有bonus,手动删掉}public Manager(String id, String name, double salary, double bonus) {//point 带全部参数的构造是父类和子类全部包含的super(id, name, salary);this.bonus = bonus;}public double getBonus() {return bonus;}public void setBonus(double bonus) {this.bonus = bonus;}@Overridepublic void work(){System.out.println("管理其他人");}
}
package a04extendsdemo4;public class Test {public static void main(String[] args) {Manager m = new Manager("1","zs",3.5,6.0);System.out.println(m.getId()+","+m.getName()+","+m.getSalary()+","+m.getBonus());m.work();m.eat();Cook c = new Cook();c.setId("2");c.setName("ls");c.setSalary(8.8);System.out.println(c.getId()+","+c.getName()+","+c.getSalary());c.work();c.eat();}}
3.多态
3.1 什么是多态及多态的应用场景
可以将子类对象赋值给父类引用!并且调用方法看具体是哪种对象,如上图如果传入teacher对象,那么调用的即为teacher的show方法。
总结:
方便去写代码,不需要像下图这样给每个类型的人都写一段单独的代码
Person类
package a01polymodemo01;public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void show(){System.out.println("Person的Name和Age: " + name + "," + age);}
}
Student类
package a01polymodemo01;public class Student extends Person {@Overridepublic void show(){System.out.println("Student的信息: " + getName()+ "," + getAge());}
}
Teacher类
package a01polymodemo01;public class Teacher extends Person {@Overridepublic void show(){System.out.println("Teacher的信息"+getName()+","+getAge());}
}
Administrator类
package a01polymodemo01;public class Administrator extends Person{public void show(){System.out.println("administrator的信息: " + getName()+ "," + getAge());}
}
测试类
package a01polymodemo01;public class Test {public static void main(String[] args) { //快捷键psvmStudent s = new Student();s.setName("xiaoa");s.setAge(21);Teacher t = new Teacher();t.setName("xiaob");t.setAge(22);Administrator a = new Administrator();a.setName("xiaoc");a.setAge(23);register(s);register(t);register(a);}//通过把参数写成父类,这个方法可以用来接收老师,学生和管理员等person下的子类。public static void register(Person p) {p.show();}
}
输出为
Student的信息: xiaoa,21
Teacher的信息xiaob,22
administrator的信息: xiaoc,23
总结:当一个方法的实参列表是一个父类的参数,那么我们调用这个方法的时候可以传入形参可以是这个父类的所有子类的对象。
3.2 多态调用成员的特点(内存图部分没看)
多态调用成员的特点
变量调用:编译看左边,运行也看左边。
方法调用:编译看左边,运行看右边。
内存图部分没有看
3.3 多态的优势和弊端
3.3.1 多态的优势
关于第一条,可以理解为如果后续需求换为person的另一个子类teacher,那么p.work这行还是可以正常执行,因为上面new那块的改了之后,p.work执行的是teacher对应的work。
关于StringBuilder和ArrayList的补充
额外补充:StringBuilder可以存放任意对象
StringBuilder 提供的 append(Object obj) 方法的参数类型是 Object。
在 Java 里,任何类都是 Object 的子类,所以可以传入任意类型的对象。
传入的对象会自动调用它的 toString() 方法,把它变成字符串,再追加到 StringBuilder 的内部字符序列中。
StringBuilder sb = new StringBuilder();
sb.append("Hello "); // String
sb.append(123); // int(自动装箱成 Integer)
sb.append(45.67); // double(自动装箱成 Double)
sb.append(true); // boolean
sb.append(new Person("zs")); // 自定义对象System.out.println(sb);
额外补充:不添加泛型,ArrayList也可以存放任意对象
3.3.2 多态的弊端以及解决办法
弊端:
不能调用子类的特有功能
解决方案
转成其他的类型会报错
进一步检查方法
新特性
3.4 多态综合练习
Animal.java
package a02polymodemo02;public class Animal {private int age;private String color;public Animal() {}public Animal(int age, String color) {this.age = age;this.color = color;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public void eat(String sth) {System.out.println("动物在吃"+sth);}
}
Dog.java
package a02polymodemo02;public class Dog extends Animal {//成员变量和父类一致,不需要写//需要写构造方法public Dog() { //子类构造方法全选之后选择OK会直接生成空参和全参的}public Dog(int age, String color) {super(age, color);}//重写的成员方法@Overridepublic void eat(String sth){System.out.println(getAge()+"岁"+getColor()+"色的狗在吃"+sth);}//独有的成员方法public void lookHome(){System.out.println("狗看家");}
}
Cat.java
package a02polymodemo02;public class Cat extends Animal {public Cat() {}public Cat(int age, String color) {super(age, color);}//重写的成员方法@Overridepublic void eat(String sth){System.out.println(getAge()+"岁"+getColor()+"色的猫在吃"+sth);}//独有的成员方法public void catchMouse(){System.out.println("猫抓老鼠");}}
Person.java
package a02polymodemo02;public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}//keepPetpublic void keepPet(Animal a, String sth){if(a instanceof Dog d){d.eat(sth);}else if(a instanceof Cat c){c.eat(sth);}}}
Test.java
package a02polymodemo02;public class Test {public static void main(String[] args) {Dog d = new Dog(2,"黑");Cat c = new Cat(3,"白");Person p = new Person();p.keepPet(d,"狗粮"); //形参是animal,因此可以传入所有animal的子类p.keepPet(c,"猫粮");}
}
输出
2岁黑色的狗在吃狗粮
3岁白色的猫在吃猫粮
4.包、final、权限修饰符、代码块
4.1 包
什么是包?
包就是文件夹。用来管理各种不同功能的Java类,方便后期代码维护。
正经的话肯定创建也得全写,但是太复杂,所以用import语句就可以
重点!
4.2 final
4.2.1 final修饰方法
表示规则,不想被别人改变,那么一般方法会用final修饰
4.2.2 final修饰类
String类也是用final修饰的
以上两种一般自己不常写
4.2.3 final修饰变量(常量)
修改会报错,因为常量只能赋值一次
比如圆周率就会用final修饰
4.2.4 关于常量(学了内存相关的内容可以再来理解一下这里)
final修饰基本类型
平时给变量命名不建议用下划线,因为下划线常量用得更多
增强switch代码可读性,有点类似宏定义
final修饰引用类型
对象
setName和setAge都没问题,get方法也不会报错,但是要注意不可以再new一个了!(对象记录的东西可以变,地址值不能变)
数组
数组地址不能变,但是记录的东西可以变
4.3 权限修饰符
4.4 代码块
写在方法里面的一段单独的大括号,用完立马回收,不占用内存
构造代码块
写在成员位置的代码块,优先于构造方法执行
可以把多个构造方法中重复的代码写在这里
目前要被淘汰了,不够灵活,因为有的构造方法和其他的是没有重复代码的,而现在这样每次创建对象都会执行这段代码
新方式:
(1)通过this调用其他构造方法(null和0是有参构造的默认值)
(2)抽取为方法,谁用谁调用
静态代码块(重点)
可以看出来只执行了一次
5.抽象类
在封装和继承的基础上,出现了父类不能确定每个子类中具体方法体的问题
(1)抽象类不能创建对象(如果能创建,那就能调用抽象类里面的方法了,但是抽象类的方法没有方法体呀)
(2)关于构造方法:抽象类的构造方法就是用来给子类调用的(子类不能继承父类的构造方法,但是可以调用)
案例:
不要下意识觉得父类一定是抽象的,具体情况具体分析
Animal父类
package a02abstract02;public abstract class Animal {String name;int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void drink() {System.out.println("喝水");}public abstract void eat();
}
frog子类
package a02abstract02;public class frog extends Animal {public frog() {}public frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙吃虫子");}
}
Dog子类
package a02abstract02;public class Dog extends Animal {public Dog() {}public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("狗吃骨头");}
}
Sheep子类
package a02abstract02;public class Sheep extends Animal {public Sheep() {}public Sheep(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("羊吃草");}
}
如果只是每个子类自己写自己的不适用抽象类,容易导致代码不统一不一致
继承抽象类一般都是重写所有抽象方法,不然使用第二种,还需要写别的子类
6.接口
兔子不会游泳,写在动物类里不合适,所以可以定义接口,这样青蛙类和狗类就可以按照接口里面定义的规则写代码,保证代码规范的统一。接口可以理解为规则
抽象类是父类,表示一类事物。而接口更侧重于表示一类行为
。
6.1 接口的定义和使用
一个类可以实现多个接口,也可以在继承一个类的同时实现多个接口。
案例
接口定义成类的话,把class改成interface就可以了
Animal父抽象类
package a01interface01;public abstract class Animal {String name;int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public abstract void eat();
}
Swim接口
package a01interface01;public interface Swim {public abstract void swim();
}
Rabbit
package a01interface01;public class Rabbit extends Animal {public Rabbit() {}public Rabbit(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("兔子吃草");}
}
Dog
package a01interface01;public class Dog extends Animal implements Swim{@Overridepublic void eat() {System.out.println("狗吃骨头");}@Overridepublic void swim() {System.out.println("狗刨");}
}
Frog
package a01interface01;public class Frog extends Animal implements Swim{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙吃虫");}@Overridepublic void swim() {System.out.println("青蛙游泳");}
}
测试类
package a01interface01;public class Test {public static void main(String[] args) {Frog f = new Frog("qing",12);f.eat();f.swim();System.out.println(f.getAge()+","+f.getName());}
}
6.2 接口和类之间的关系
以下是说明类和接口的关系,可以实现多个接口
多个接口中有重名的方法,只需要重写一次就行。这个重写可以相当于是重写了两个接口的方法。
以下是说明接口和接口的关系
如果实现类实现了最下面的子接口,那么需要实现所有的抽象方法
三个接口里面的方法都需要实现
案例
以下这种太过杂乱
第一种思路
第二种思路
Person
最后把Person也定义为抽象类,因为现在不行让外界直接创造人的对象,直接创建顶层父类人的对象此时没有意义
package a03interface03;public class abstract Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
Sporter
package a03interface03;public abstract class Sporter extends Person{public Sporter() {}public Sporter(String name, int age) {super(name, age);}public abstract void learn();
}
Coach
package a03interface03;public abstract class Coach extends Person {public Coach() {}public Coach(String name, int age) {super(name, age);}public abstract void teach();
}
speakEnglish接口
package a03interface03;public interface speakEnglish {public abstract void talkEnglish();
}
PingPangSporter
package a03interface03;public class PingPangSporter extends Sporter implements speakEnglish{public PingPangSporter() {}public PingPangSporter(String name, int age) {super(name, age);}@Overridepublic void learn() {System.out.println("PingPangSporter learn");}@Overridepublic void talkEnglish() {System.out.println("PingPangSporter talkEnglish");}
}
BasketBallSporter
package a03interface03;public class BasketBallSporter extends Sporter implements speakEnglish{public BasketBallSporter() {}public BasketBallSporter(String name, int age) {super(name, age);}@Overridepublic void learn() {System.out.println("篮球运动员学习");}@Overridepublic void talkEnglish() {System.out.println("篮球运动员说英语");}
}
PingPongCoach
package a03interface03;public class PingPongCoach extends Coach {public PingPongCoach() {}public PingPongCoach(String name, int age) {super(name, age);}@Overridepublic void teach() {System.out.println("PingPongCoach teach");}
}
BasketballCoach
package a03interface03;public class BasketballCoach extends Coach {public BasketballCoach() {}public BasketballCoach(String name, int age) {super(name, age);}@Overridepublic void teach() {System.out.println("BasketballCoach teach");}
}
6.1.1 接口多学三招
默认方法
静态方法
私有方法
用于给接口内部方法使用,不需要给外类访问
上面默认私有方法,下面静态私有方法
6.1.2 接口的应用
想让某个JavaBean实现某个功能,那就让接口去实现这个功能就可以了
因为车的对象和搬家公司都实现了运输这个接口,所以在搬家这个方法中,车的对象和搬家公司对应的对象都可以作为参数传入。
接口多态!!!
6.1.2 适配器设计模式
如果这个类不想实现接口里的所有抽象方法(因为只需要用到一部分),可以新建一个适配器类(一般也会写为抽象类,因为建它的实体没有意义)去implements接口,对接口中的所有方法进行空实现,这样后面的类可以直接继承这个适配器类,这个时候需要用到哪个方法就重写哪个方法。
7.内部类
7.1 内部类的概念
Car.java
package a01innerclassdemo1;public class Car {String carName;int carAge;String carColor;public void show(){System.out.println(carName);Engine e = new Engine();System.out.println(e.engineName);}class Engine{String engineName;int engineAge;public void show(){System.out.println(engineName);System.out.println(carName);}}}
Test.java
package a01innerclassdemo1;public class Test {public static void main(String[] args) {Car c = new Car();c.carName = "bl";c.carAge = 12;c.carColor = "red";c.show();}
}
7.2 内部类的分类
成员内部类(用得少,内存图没有看)
同理,一旦私有,只能在外部类的内部创建对象,在外面就不能用了。
不加的话,是默认权限,只能在本包中用。protected和public同理
第二种:
Outer.Inner oi = new Outer().new Inner();
第一种(尤其针对于内部类是私有的很合适)
可以用object x = 这个作为承接,因为object 是所有类的父类
每个 Outer 实例都有自己独立的 成员方法副本。当你创建一个 Inner 实例时,它必须知道自己是属于 outer1 还是 outer2 的,才能正确地访问 成员方法。
静态内部类和局部内部类(用得少)
注意需要创建外部类对象才能访问非静态的
局部内部类
这里的局部变量指的是所在方法里的局部变量
匿名内部类(用得多)
这一段整体其实是new出来的对象,真正的没有名字的匿名内部类指的是紫色框柱的大括号包裹的那一块,这个紫框(没有名字的类)和Swim之间是实现关系(因为是接口,所以是实现,如果是类那就是继承),方法重写在内部,创建对象指的是new红色箭头创建了这个没有名字的类的对象,然后()也是创建对象代码中需要有的。
整体可以理解为对应名字那个接口的实现类对象,或者是对应名字的类的子类对象
在项目总目录下会有out文件,里面装了所有的字节码文件,点开同名的包名,就能找到。
以下Test$1和Test$2就是给匿名内部类,这两个名字是编译器起的名字
反编译出现这个匿名类
(注意,可以直接把目录拖入终端,就可以在终端打开这个目录)
作为类的子类对象和接口的实现类对象,存在多态的用法。方法的参数是接口或者类的时候,可以直接在调用的时候写一次匿名内部类,这样不需要额外写一个类文件,并且通过多态机制,这个新写的类可以直接作为参数传入。
多态: 作为参数和直接赋值本质上都是 父类 f = new 子类();
Animal类
package a02innerclassdemo2;public abstract class Animal {public abstract void eat();
}
Swim接口
package a02innerclassdemo2;public interface Swim {public void swim();
}
Test类(核心)
package a02innerclassdemo2;public class Test {public static void main(String[] args) {//整体可以理解为Swim接口的实现类的对象new Swim(){@Overridepublic void swim() {System.out.println("重写Swim中的swim方法");}};//同样存在接口多态,如下//左边是Swim对象,右边是接口实现类的对象!! 同样是父类 f = new 子类();Swim s = new Swim(){@Overridepublic void swim() {System.out.println("重写Swim中的swim方法");}}; //直接在这里.swim()进行调用也是可以的,可以调用自己的类!!s.swim(); //编译看左边,运行看右边//整体可以理解为Animal类的子类的对象new Animal(){@Overridepublic void eat() {System.out.println("重写Animal中的eat方法");}};//之前调用方式://创建Animal的子类Dog类继承Animal//创建Dog类的对象,传递给method//如果Dog类只需要用一次,那么单独定义一个类不划算method(//以下就是一个Animal的子类对象,相当于是把这个对象当做参数传递给method//point 多态new Animal(){@Overridepublic void eat() {System.out.println("狗吃骨头");}});}public static void method(Animal a){// Animal a = 子类对象-》多态a.eat(); //编译看左边,运行看右边}
}