文章目录
- 斜体样式1.1 面向对象三大特征 ?
- 1.2 什么是多态 ?*斜体样式*
- 1.3 多态的前提
- 1.4 多态的成员访问特点
- 1.5 多态的优缺点
- 1.6 多态的转型
- 1.7 多态的转型注意
- 1.8 解决转型安全隐患
- 2 内部类
- 2.1 内部类的分类
- 什么是内部类 ?
- 什么时候使用内部类 ?
- 内部类分类 ?
- 2.2 成员内部类
- 成员内部类访问外部类的成员
- 2.3 匿名内部类
斜体样式1.1 面向对象三大特征 ?
- 封装 , 继承 , 多态
1.2 什么是多态 ?斜体样式
-
一个对象在不同时刻体现出来的不同形态
-
举例 : 一只猫对象
- 我们可以说猫就是猫 : Cat cat = new Cat();
- 我们也可以说猫是动物 : Animal cat = new Cat();
- 这里对象在不同时刻,体现出来的不同形态 , 我们就可以理解为多态
1.3 多态的前提
- 有继承/实现关系
- 有方法重写
- 父类的引用指向子类的对象
/*多态的三个前提条件1 需要有继承/实现关系2 需要有方法重写3 父类的引用指向子类的对象*/
public class AnimalTest {public static void main(String[] args) {// 3 父类的引用指向子类的对象// 多态形式对象Animal a = new Cat();}
}class Animal{public void eat(){System.out.println("吃东西");}
}class Cat extends Animal{@Overridepublic void eat() {System.out.println("猫吃鱼....");}
}
1.4 多态的成员访问特点
- 构造方法 : 和继承一样 , 子类通过super()访问父类的构造方法
- 成员变量 : 编译看左边(父类) , 执行看左边(父类)
- 成员方法 : 编译看左边(父类) , 执行看右边(子类)
/*多态的成员访问特点 :1 构造方法 : 和继承一样 , 都是通过super()访问父类的构造方法2 成员变量 : 编译看左边(父类) , 执行看左边(父类)3 成员方法 : 编译看左边(父类) , 执行看右边(子类) , 注意 , 如果执行时1) 子类没有回动态去找父类中的方法2) 子类的特有方法无法进行调用(多态的缺点)*/
public class MemberTest {public static void main(String[] args) {// 父类的引用指向子类的对象Fu f = new Zi();// 多态对象调用成员变量System.out.println(f.num);// 多态对新乡调用调用成员方法f.show();// 多态对象不能调用子类特有的方法// f.show2();}
}class Fu {int num = 100;public void show() {System.out.println("父类的show方法");}
}class Zi extends Fu {int num = 10;public void show() {System.out.println("子类的show方法");}public void show2(){System.out.println("子类特有的方法");}
}
1.5 多态的优缺点
- 优点 : 提高代码的扩展性
- 缺点 : 不能调用子类特有的功能
public abstract class Animal {private String breed;private String color;public Animal() {}public Animal(String breed, String color) {this.breed = breed;this.color = color;}public String getBreed() {return breed;}public void setBreed(String breed) {this.breed = breed;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public abstract void eat();
}
public class Cat extends Animal {public Cat() {}public Cat(String breed, String color) {super(breed, color);}@Overridepublic void eat() {System.out.println("猫吃鱼...");}public void catchMouse() {System.out.println("抓老鼠...");}
}
public class Dog extends Animal {public Dog() {}public Dog(String breed, String color) {super(breed, color);}@Overridepublic void eat() {System.out.println("狗吃骨头!");}public void lookDoor(){System.out.println("狗看门...");}
}
public class Pig extends Animal {public Pig() {}public Pig(String breed, String color) {super(breed, color);}@Overridepublic void eat() {System.out.println("猪拱白菜...");}public void sleep() {System.out.println("一直再睡...");}
}
/*如果方法的参数是一个类的话 , 那么调用此方法需要传入此类的对象 , 或者子类对象多态的好处 :提高代码的扩展性 , 灵活性多态的缺点:不能调用子类的特有功能*/
public class AnimalTest {public static void main(String[] args) {useAnimal(new Cat());System.out.println("---------");useAnimal(new Dog());System.out.println("---------");useAnimal(new Pig());}public static void useAnimal(Animal a){// Animal a = new Dog()a.eat();// 多态不能访问子类特有的功能// 如果解决 ?// 向下转型if(a instanceof Cat) {Cat cat = (Cat) a;cat.catchMouse();}if(a instanceof Dog) {Dog dog = (Dog) a;dog.lookDoor();}if(a instanceof Pig) {((Pig) a).sleep();}}// // 定义一个使用猫类的方法
// public static void useAnimal(Cat c) {// Cat c = new Cat();
// c.eat();
// c.catchMouse();
// }
//
// // 定义一个使用狗类的方法
// public static void useAnimal(Dog d) {// Dog d = new Dog();
// d.eat();
// d.lookDoor();
// }
//
// // 定义一个使用猪类的方法
// public static void useAnimal(Pig pig) {
// pig.eat();
// pig.sleep();
// }
}
1.6 多态的转型
- 向上转型 : 把子类类型数据转成父类类型数据 Animal a = new Cat();
- 向下转型 : 把父类类型数据转成子类类型数据 Cat cat = (Cat)a;
1.7 多态的转型注意
-
如果被转的对象 , 对应的实际类型和目标类型不是同一种数据类型 , 那么转换时会出现ClassCastException异常
-
异常代码如下 public static void main(String[] args) {Animal a = new Cat();useAnimal(a); } public static void useAnimal(Animal a) {Dog d = (Dog) a;d.eat(); }
1.8 解决转型安全隐患
- 使用关键字 instanceof
- 作用 : 判断一个对象是否属于一种引用数据类型
- 格式 : 对象名 instanceof 引用数据类型
- 通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
2 内部类
2.1 内部类的分类
-
什么是内部类 ?
- 一个A类 中 定义一个B类 , 那么B类就属于A类的内部类 , A类就属于B类的外部类
-
什么时候使用内部类 ?
- 多个事物之间有包含关系, 可以使用内部类
-
内部类分类 ?
- 成员内部类
- 局部内部类
- 匿名内部类
2.2 成员内部类
-
定义的位置 : 类中方法外
-
创建成员内部类对象格式 : 外部类名.内部类名 对象名 = new 外部类名().new 内部类名(参数);
// 外部类 public class Person {// 成员内部类public class Heart {// 频率变量private int rate;// 跳动方法public void beats() {System.out.println("咚咚咚!");}} }class Test {public static void main(String[] args) {// 创建内部类对象Person.Heart heart = new Person().new Heart();// 调用内部类中的方法heart.beats();} }
-
成员内部类访问外部类的成员
- 在内部类中有代表外部类对象的格式 : 外部类名的.this , 私有的也可以访问
- 外部类要想访问内部类成员 , 需要创建内部类对象
public class Person {private String name = "张三";private int num = 10;// 成员内部类public class Heart {int num = 100;// 频率private int rate;// 跳动public void beats() {System.out.println("咚咚咚!");}// 调用外部类的成员public void show(){int num = 1000;System.out.println(Person.this.name);System.out.println(num);// 1000 就近原则System.out.println(this.num);// 100System.out.println(Person.this.num);// 10}} }class Test {public static void main(String[] args) {Person.Heart heart = new Person().new Heart();heart.beats();heart.show();} }
2.3 匿名内部类
- 匿名内部类 : 没有名字的类 , 一次性产品
- 使用场景 : 直接调用方法 , 作为方法的传参 , 返回值类型
- 好处 : 简化代码 , 快速实现接口或者抽象的抽象方法
- 格式 :
- new 类名/接口名(){ 重写抽象方法 } 注意 : 此处创建的是子类对象!!!
- 使用方式 :
- 直接调用方法
- 作为方法的参数传递
- 作为方法的返回值类型
//接口
interface Flyable {void fly();
}
// 直接调用方法
Flyable f1 = new Flyable() {@Overridepublic void fly() {System.out.println("不知道什么在飞.....");}
};
f1.fly();
// 作为方法的参数传递
showFlyable(new Flyable() {@Overridepublic void fly() {System.out.println("不知道什么在飞3333");}}
);public static void showFlyable(Flyable flyable) {flyable.fly();
}
// 作为方法的返回值类型
public static Flyable getFlyable() {return new Flyable() {@Overridepublic void fly() {System.out.println("3333333333333");}};
}
/*1 如果方法的参数是一个类的话 , 调用此方法需要传入此类的对象或者此类的子类对象2 如果方法的返回值类型是一个类的话 , 需要返回此类的对象 , 或者此类的子类对象3 如果方法的参数是一个接口的话 , 调用此方法需要传入此接口的实现类对象4 如果方法的返回值类型是一个接口的话 , 需要返回此接口的实现类对象匿名内部类 : 代表的就是子类对象!!!new 类名/接口名(){重写抽象类或者接口中的抽象方法};使用方向 :1 调用方法2 作为方法参数传递3 作为方法的返回值*/
public interface Swim {public abstract void swimming();
}class Test {public static void main(String[] args) {
// // 子类对象!!!// 1 调用方法
// new Swim() {
// @Override
// public void swimming() {
// System.out.println("匿名内部类 , 重写了接口中的抽象方法...");
// }
// }.swimming();// // 2 作为方法参数传递
// useSwim(new Swim() {
// @Override
// public void swimming() {
// System.out.println("匿名内部类 , 重写了接口中的抽象方法...");
// }
// });// // 3 作为方法的返回值
// Swim s = getSwim();
// s.swimming();}public static Swim getSwim() {return new Swim() {@Overridepublic void swimming() {System.out.println("匿名内部类 , 重写了接口中的抽象方法...");}};}/*Swim swim = new Swim() {@Overridepublic void swimming() {System.out.println("匿名内部类 , 重写了接口中的抽象方法...");}};*/public static void useSwim(Swim swim) {swim.swimming();}
}