目录
一. this和super关键字
1. this关键字
2. super关键字
二. 重写
三. final关键字
四. 多态
五. 抽象类
1. 抽象方法
2. 抽象类
3. 面向抽象设计
一. this和super关键字
1. this关键字
this 当前对象的引用
this.属性 this.方法名() this() -- 调用构造函数 放在代码第一行
细节:
●可以用
this
来区分属性和局部变量。●在类的方法中,我们可以使用this.属性或this.方法的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略this.。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用this.变量的方式,表明此变量是属性,而非形参。
●使用this访问属性和方法时,如果在本类中未找到,会从父类中查找。调用属性和方法:
class Person{ // 定义Person类 private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; } public void getInfo(){ System.out.println("姓名:" + name) ; this.speak(); } public void speak(){ System.out.println(“年龄:” + this.age); } }
调用构造方法:
●this(形参列表)必须声明在当前构造器的首行
class Person{ // 定义Person类 private String name ; private int age ; public Person(){ // 无参构造器 System.out.println("新对象实例化") ; } public Person(String name){ this(); // 调用本类中的无参构造器 this.name = name ; } public Person(String name,int age){ this(name) ; // 调用有一个参数的构造器 this.age = age; } public String getInfo(){ return "姓名:" + name + ",年龄:" + age ; } }
2. super关键字
super 子类调用父类的内容
super 表示的是超类或者父类的意思
super.属性 调用父类的成员变量 super.方法名() 调用父类的成员方法 super() 调用父类的构造方法
使用:
可以在子类中显示地调用父类的结构。
构造方法里面:
●子类默认调用父类无参构造方法super()●如果父类没有无参构造,则需要手动使用super(参数)来调用父类的有参构造
●如果显示的写了super(参数),默认的则不赠送
●super()一定是在第一行
●this()必须写在第一行,所以super()和this()不能同时出现父类:
public class Person { protected String name; protected int age; public String getName() { return name; } public Person(String name, int age) { super(); this.name = name; this.age = age; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
子类:
public class Student extends Person { private int score; public Student() { //默认调用父类无参构造方法 // super(); //调用父类的有参构造方法 super("zkt",18); } }
二. 重写
在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为重写(Override)
语法规则:在子类和父类中有方法名完全一致,返回值类型相同的方法
●发生在子类和父类中,如果父类所提供的方法不能满足子类的需求,则子类可以重写
●方法名相同,参数项相同,返回值也相同,子类的修饰符>=父类的修饰符,方法体不同返回值:子类重写的方法的返回值范围可以小于父类的方法的返回值范围
父类:
class Person { public void run() { System.out.println("Person.run"); } }
子类: 在子类Student中,重写这个run()方法
class Student extends Person { @Override public void run() { System.out.println("Student.run"); } }
手动重写Object类的方法:
在Java中,所有的class类最终都继承自Object,而Object定义了几个重要的方法
@Override public String toString() { return "姓名" + name + "身份证号:" + cardId; } // equals 只能用在引用数据类型上 // object中的equals方法比较的是两个对象的地址是否相同,String类比较的是内容是否相同(因为其重写了equals方法) // 如果自己想要看内容是否相同 重写equals方法 @Override public boolean equals(Object obj) { // 1.先比较地址是否相同 if (this == obj) { return true; } // 2.先判断是否是Person类型 if (obj instanceof Person) { // 向下转型 Person p1 = (Person) obj; return this.name.equals(p1.name) && this.cardId.equals(p1.cardId); } return false; } // 地址改成了属性的地址和 // 如果两个对象的属性完全相同 则hashCode值也完全相同 @Override public int hashCode() { return name.hashCode()+cardId.hashCode(); }
重载:
●方法的重载:在同一个类中,方法名相同,参数项不同(类型,个数,顺序)
●和返回值无关,发生在编译期
区别:
N 区别 重载 重写 1 概念 方法名称相同,参数的类型及个数不同 方法名称、返回值类型、参数的类型及个数完全相同 2 范围 一个类 继承关系 3 限制 没有权限要求 被重写的方法不能拥有比父类更严格的访问控制权限
三. final关键字
继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。
父类:
public class Fu { public final int AGE = 18; public final int[] AAA = { 12, 2, 23, 45 }; public final void eat() { System.out.println("这个是父类的eat方法"); } }
1.1:final用来修饰字段基本数据类型,常量-值不可变
//1.1:final用来修饰字段基本数据类型,常量-值不可变 Fu fu1 =new Fu(); // fu1.AGE=10; System.out.println(fu1.AGE);//18
1.2:final用来修饰字段(引用数据类型)地址不可发生变化,值可以变
fu1.AAA[0]=1000; System.out.println(Arrays.toString(fu1.AAA));//[1000, 2, 23, 45]
2.final用来修饰方法,此方法不能重写,此方法可以被子类调用
//2.final用来修饰方法,此方法不能重写,此方法可以被子类调用 Zi zi = new Zi(); zi.eat();//这个是父类的eat方法
class Zi extends Fu{ // compile error: 不允许覆写 @Override public void eat() { System.out.println("这个是子类的eat方法"); } }
3.fianl用来修饰类,父类不能被继承,太监类
四. 多态
多态指的是同一对象,在不同时刻表现出来的多种形态
多态实现的三要素:
●有继承关系/实现关系
●有方法的重写
●有父类的引用指向子类,向上转型
示例:
Shape类:
public class Shape { public void draw() { } }
子类:
class Circle extends Shape { @Override public void draw() { System.out.println("⭕"); } } class Flower extends Shape { @Override public void draw() { System.out.println("❀"); } } class Star extends Shape { @Override public void draw() { System.out.println("⭐"); } } class Triangle extends Shape { @Override public void draw() { System.out.println("▲"); } } class Square extends Shape { @Override public void draw() { System.out.println("■"); } }
不使用多态写法:
public static void main(String[] args) { Flower flower = new Flower(); Star star = new Star(); Circle circle = new Circle(); Triangle triangle = new Triangle(); Square square = new Square(); String[] shapeStrings = { "flower", "star", "circle", "triangle", "square" }; // 不使用多态绘制图形 for (int i = 0; i < shapeStrings.length; i++) { if ("flower".equals(shapeStrings[i])) { flower.draw(); } else if ("star".equals(shapeStrings[i])) { star.draw(); } else if ("circle".equals(shapeStrings[i])) { circle.draw(); } else if ("triangle".equals(shapeStrings[i])) { triangle.draw(); } else if ("square".equals(shapeStrings[i])) { square.draw(); } } }
多态写法:
public static void main(String[] args) { Shape[] shapes = {new Flower(),new Star(),new Triangle(),new Square()}; for (Shape shape : shapes) { shape.draw(); } }
多态的写法优点:
●类的调用者对类的使用成本进一步降低,多态是让类的调用者不用知道类的具体类型.
●可以降低圆圈复杂度
●可拓展性增强多态的写法:
父类 对象名= new 子类() #父类类型指向子类对象 eg: Fu fu = new Zi() 接口 对象名= new 实现类() #接口类型指向实现类对象
多态中的成员访问特点:见java基础09
●成员变量的访问特点:编译看左边,运行看左边,如果没有则向上查找。
●成员方法的访问特点: 编译看左边,运行看右边,如果没有则向上查找。
多态的优缺点:
●优点:父类类型/接口类型作为方法的参数/返回值,提高了程序的扩展性
●缺点:无法访问子类/实现类中独有的方法。(需要向下转型)
向上下转型:见java基础09
五. 抽象类
●当一个类被abstract修饰这个类就是抽象类
●在Java中,—个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
1. 抽象方法
抽象方法:
●抽象方法没有方法体
●抽象方法使用abstract关键字来修饰,修饰符和返回值中间
●抽象方法必须写在抽象类中
●抽象方法的修饰符不能是privatepublic abstract class Shape { // 定义了一个"规范" public abstract void draw(); }
2. 抽象类
抽象类:
●抽象类使用abstract关键字来修饰,放在修饰符和class中间
●子类必须要重写抽象类中的抽象方法,除非子类也是抽象类
●抽象类无法实例化对象
●抽象类中成员变量,常量,构造方法(存在的意义,初始化成员变量)public abstract class Shape { public int age; public final double PI = 3.14; public Shape() { this.age = 18; System.out.println("这个是父类的无参构造方法"); } // 定义了一个"规范" public abstract void draw(); public void doSth() { System.out.println("这个是shape的doSth方法"); } }
●子类是抽象类,可以不用实现抽象方法,当然也可以实现抽象方法(如果在此处可以完成)
//子类是抽象类,可以不用实现抽象方法,当然也可以实现抽象方法(如果在此处可以完成) abstract class Circle extends Shape { }
●子类是普通类,必须要重写父类中的抽象方法
//子类是普通类,必须要重写父类中的抽象方法 class Flower extends Shape { public Flower() { super(); } @Override public void draw() { System.out.println("❀"); } }
●抽象类不能实例化对象
报错
Circle c1 =new Circle();//抽象类不能实例化对象 Shape s1 = new Shape();
子类调用:
Flower f1 = new Flower(); System.out.println(f1.age); f1.doSth();
多态写法:
Shape s1 = new Flower();//多态写法 s1.doSth(); s1.draw();
3. 面向抽象设计
面向抽象设计的本质是:
●上层代码只定义规范(例如:abstract class Person)
●不需要子类就可以实现业务逻辑(正常编译)
●具体的业务逻辑由不同的子类实现,调用者并不关心public abstract class Person { protected String name; public Person(String name) { super(); this.name = name; } // 定义了规范 public abstract void run(); } class Student extends Person { public Student(String name) { super(name); } @Override public void run() { System.out.println("学生类"+name+"的run方法"); } } class Teacher extends Person{ public Teacher(String name) { super(name); } @Override public void run() { System.out.println("老师类"+name+"的run方法"); } }
这种引用抽象类的好处在于,我们对其进行方法调用,并不关心Person类型变量的具体子类型:
Person[] persons = { new Student("zkt1"), new Student("zkt2"), new Teacher("zkt3") }; for (Person person : persons) { //在运行的过程中,不必过多关注子类的业务实现,也不必关注子类的具体类型 person.run(); }