继承
继承主要解决代码重用问题,利用继承可以从已有的类继续继承派生出新的子类,也可以利用子类扩展出更多的操作功能。
继承的实现
/*
class 子类 extends 父类{}
子类又称为派生类
父类又称为超类
*/
class Person{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
/*getter省略 */
public Person(){}
public Person(String name){
this();
this.name = name;
}
public Person(String name, int age){
this(name);
this.age = age;
}
public String getInfo(){
return "name:" + this.name + "\t age:" + this.age;
}
}
class Student extends Person{
private String school;
public void setSchool(String school){
this.school = school;
}
}
public class Text{
public static void main(String args[]){
Student stu = new Student();
stu.setName("小明"); //子类可以使用父类的方法
stu.setAge(20);
stu.setSchool("清华"); //子类也可以扩展自己的功能
System.out.print(stu.getInfo());
}
}
继承的限制
- java不允许多重继承,但是允许多层继承
//多层继承
class A{}
class B extends A{}
class C extends B{}
- 子类在继承父类时,会继承父类中的全部操作,但是对于所有的私有操作属于隐式继承,而所有的非私有操作属于显式继承
- 在子类对象构造前,一定会默认调用父类的构造,以保障父类对象先实例化,子类对象后实例化
super关键字
super()可以调用在子类构造方法中调用父类的构造方法
class Person{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
/*getter省略 */
public Person(){}
public Person(String name){
this();
this.name = name;
}
public Person(String name, int age){
this(name);
this.age = age;
}
public String getInfo(){
return "name:" + this.name + "\t age:" + this.age;
}
}
class Student extends Person{
private String school;
public Student(String name,int age){
super(name,age);//使用super调用父类的构造方法
}
public void setSchool(String school){
this.school = school;
}
}
public class Text{
public static void main(String args[]){
Student stu = new Student("小明",22);
System.out.print(stu.getInfo());
}
}
super().父类方法(),可以在子类中调用父类的方法。
class A{
public void print(){
System.out.print("父类方法");
}
}
class B extends A{
public void print(){
super().print();//调用父类的方法
System.out.print("父类方法");
}
}
覆写
如果子类定义的方法和属性,在父类中出现同名时,这样的操作就叫做覆写。
class A{
public void fun(){
System.out.print("A类的fun方法");
}
}
class B extends A{
public void fun(){
System.out.print("B类中的fun方法");
}
}
//那么当B类定义了一个和A类完全一样的fun方法时,实例化B类对象,调用fun方法则是B类覆写过的方法。
覆写原则:如果子类覆写了方法,并且实例化子类对象,那么调用的一定是被覆写的方法。
覆写限制:被之类覆写的方法不能拥有比父类更严格的访问控制权限。public > default > private
属性的覆写在实际开发中没有意义,因为类中的属性都是private封装,那么一旦封装后属性覆写没有意义,父类定义的私有属性子类根本看不见,更不会互相影响。
this和super的区别
- this调用本类构造方法、本类方法、本类属性。
- super调用父类构造方法、父类方法、父类属性
final关键字
final称之为终结器,可以使用final定义类、方法和属性。
- 使用final定义的类不能再有子类,即任何类不能继承以final声明的父类。一般情况下不使用final定义类。
- 使用final定义的方法不能被子类所覆写
- 使用final定义的变量就称为了常量,不能修改。
final int i = 10;
i = 100;//错误,不能修改常量
//全局常量:
public static final String MSG = "heloo";
多态
多态性在开发中有两个方法:
- 方法的多态性:重载和覆写
重载:同一个方法名称,根据不同参数类型即个数可以完成不同功能。
覆写:同一个方法,根据实例化的子类对象不同,所完成的功能不同 - 对象的多态性:父子类对象的转换
向上转型:子类对象变成父类对象:父类 父类对象 = 子类实例,自动转换
向下转型:父类对象变成子类对象:子类 父类对象 = (子类) 父类实例
向上转型:子类对象变成父类对象
class A{
public void print(){
System.out.print("父类print方法");
}
}
class B extends A{
public void print(){
System.out.print("子类print方法");
}
}
A a = new B();//向上转型,子类对象变成父类对象
a.print();//调用的是子类覆写过的方法
向下转型:父类对象变成子类对象
class A{
public void print(){
System.out.print("父类print方法");
}
}
class B extends A{
public void print(){
System.out.print("子类print方法");
}
}
A a = new B();
B b = (B) a;//向下转型,父类对象变成子类对象
b.print();//调用的是子类覆写过的方法
//向下转型是有前提条件的:必须发生向上转型后才可以向下转型。
//如果是两个没有关系的对象发送强制转换,则会异常。
抽象类
利用抽象类可以明确地定义子类需要覆写地方法,这样代码开发也就更加标准。
抽象类定义
抽象方法使用abstract关键字定义,拥有抽象方法的类一定属于抽象类。
abstract class A{ //定义抽象类
public void fun(){
//普通方法
}
//没有方法体,并且存在abstract关键字表示抽象方法
public abstract void print();
}
class B extends A{
public void print(){
//子类必须强制要求覆写此方法
}
}
接口
利用抽象类可以实现子类覆写方法的控制,但是抽象类有很大一个问题:单继承限制。所以为了打破这个限制,需要使用Java接口来解决。
接口的定义
使用interface关键字进行接口的定义
interface A{
public static final String MSG = "ttt";//全局常量
public abstract void print();//抽象方法
}
接口使用原则:
- 接口必须有子类,但是此时子类可以使用implements关键字实现多个接口,避免单继承限制。
- 接口的子类必须要覆写接口中的全部抽象方法
- 接口的对象可以利用子类对象的向上转型进行实例化操作
interface A{
public abstract void print();
}
interface B{
public abstract void get();
}
class X implements A,b{ //X类实现A、B接口
public void print(){
//覆写A接口的抽象方法
}
public void get(){
//覆写B接口的抽象方法
]
}
X x = new X(); //实例化子类
A a = x; //向上转型
B b = x; //向上转型
a.print(); //调用被覆写过的方法