【修饰符】 class 父类 { ... } 【修饰符】 class 子类 extends 父类 { ... }
继承特点:成员变量
私有化(private)
-
父类中的成员,无论是公有(public)还是私有(private),均会被子类继承。
-
子类虽会继承父类私有(private)的成员,但子类不能对继承的私有成员直接进行访问,可通过继承的公有方法进行访问(setxxx&getxxx)。如图所示:
class Animal { // 定义name属性 private String name; // 定义age属性 public int age; // 定义动物的吃东西方法 public void eat() { System.out.println(age + "岁的" + name + "在吃东西"); } } /* * 定义猫类Cat 继承 动物类Animal */ class Cat extends Animal { // 定义一个猫抓老鼠的方法catchMouse public void catchMouse() { System.out.println("抓老鼠"); } } /* * 定义测试类 */ public class ExtendDemo01 { public static void main(String[] args) { // 创建一个猫类对象 Cat cat = new Cat(); // 为该猫类对象的name属性进行赋值 //t.name = "Tom";// 编译报错 // 为该猫类对象的age属性进行赋值 t.age = 2; // 调用该猫的catchMouse()方法 t.catchMouse(); // 调用该猫继承来的eat()方法 t.eat(); } }
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的
成员变量重名
如果子类父类中出现重名的成员变量,这时的访问是有影响的
class Fu { // Fu中的成员变量。 int num = 3; } class Zi extends Fu { // Zi中的成员变量 int num = 4; public void show() { // 访问的num到底是子类还是父类? System.out.println("num = " + num); } } class ExtendsDemo03 { public static void main(String[] args) { // 创建子类对象 Zi z = new Zi(); // 调用子类中的show方法 z.show(); } } 演示结果: num = 4
承接上例子类方法需要修改,代码如下:
class Zi extends Fu { // Zi中的成员变量 int num = 6; public void show() { //访问父类中的num System.out.println("Fu num=" + super.num); //访问子类中的num System.out.println("Zi num=" + this.num); } } 演示结果: Fu num = 5 Zi num = 6
成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法
成员方法重名——重写(Override)
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。
class Fu { public void show() { System.out.println("Fu show"); } } class Zi extends Fu { //子类重写了父类的show方法 public void show() { System.out.println("Zi show"); } } public class ExtendsDemo05{ public static void main(String[] args) { Zi z = new Zi(); // 子类中有show方法,只执行重写后的show方法 z.show(); // Zi show } }
在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找。
注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
重写(Override)
概念:在继承关系当中,方法的名称一样,参数列表也一样。
重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
重载(Overload):方法的名称一样,参数列表【不一样】。
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
方法覆盖重写的注意事项:见下面
重写的应用
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。比如新的手机增加来电显示头像的功能,代码如下:
class Phone { public void sendMessage(){ System.out.println("发短信"); } public void call(){ System.out.println("打电话"); } public void showNum(){ System.out.println("来电显示号码"); } } //智能手机类 class NewPhone extends Phone { //重写父类的来电显示号码功能,并增加自己的显示姓名和图片功能 public void showNum(){ //调用父类已经存在的功能使用super super.showNum(); //增加自己特有显示姓名和图片功能 System.out.println("显示来电姓名"); System.out.println("显示头像"); } } public class ExtendsDemo06 { public static void main(String[] args) { // 创建子类对象 NewPhone np = new NewPhone(); // 调用父类继承而来的方法 np.call(); // 调用子类重写的方法 np.showNum(); } }
注意事项
-
必须保证父子类之间方法的名称相同,参数列表也相同。 @Override:写在方法前面,用来检测是不是有效的正确覆盖重写。 这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。
-
子类方法的返回值类型必须【小于等于】父类方法的返回值类型(小于其实就是是它的子类)。 小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。
注意:如果返回值类型是基本数据类型和void,那么必须是相同
-
子类方法的权限必须【大于等于】父类方法的权限修饰符。 小扩展提示:public > protected > 缺省 > private 备注:缺省不是汉字缺省,而是什么都不写,留空。
-
几种特殊的方法不能被重写
-
静态方法不能被重写
-
-
final方法不能被重写
-
继承的特点三:构造方法
首先我们要回忆两个事情,构造方法的定义格式和作用。
-
构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
-
构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个
super()
,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。代码如下:
class Fu { private int n; Fu(){ System.out.println("Fu()"); } } class Zi extends Fu { Zi(){ // super(),调用父类构造方法 super(); System.out.println("Zi()"); } } public class ExtendsDemo07{ public static void main (String args[]){ Zi zi = new Zi(); } } 输出结果: Fu() Zi()
1、要创建一个类的实例对象,必须调用一个对象的构造器,来完成类的实例初始化过程。实例初始化过程就是为实例变量赋初始值的过程。 2,当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。 3,无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法,一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。
示例
public class Person { private String name; private int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } //其他成员方法省略 } public class Student extends Person{ private int score; public Student(String name, int age) { super(name, age); } public Student(String name, int age, int score) { super(name, age); this.score = score; } //其他成员方法省略 }
父类空间优先于子类对象产生
public class Person { private String name; private int age; //其他代码省略 } public class Student extends Person{ private int score; //其他成员方法省略 } public class Test{ public static void main(String[] args){ Student stu = new Student(); } }
-
super :代表父类的存储空间标识(可以理解为父亲的引用)。
-
通过super找成员变量和成员方法时,直接从父类空间(包含父类的父类继承的)找
-
super()或super(实参列表)只能从直接父类找
-
通过super只能访问父类在子类中可见的(非private,跨包还不能是缺省的)
-
-
this :代表当前对象的引用。
-
通过this找成员变量和成员方法时,先从当前类中找,没有的会往上找父类的。
-
但是this()或this(实参列表)只会在本类中找
-
注意:super和this都不能出现在静态方法和静态代码块中,因为super和this都是存在与对象
1、super.成员变量
在子类对象中访问父类空间的成员变量,即访问从父类继承的在子类中仍然可见的成员变量
1)子类没有与父类重名的成员变量
public class Test{ public static void main(String[] args){ Son s = new Son(); s.test(); } } class Father{ int a = 10; } class Son extends Father{ public void test(){ System.out.println(super.a);//10 System.out.println(this.a);//10 System.out.println(a);//10 } }
2)子类有与父类重名的成员变量
public class Test{ public static void main(String[] args){ Son s = new Son(); s.test(); } } class Father{ int a = 10; } class Son extends Father{ int a = 20; public void test(){ System.out.println(super.a);//10 System.out.println(this.a);//20 System.out.println(a);//20 } }
3)方法有局部变量与成员变量重名
public class Test{ public static void main(String[] args){ Son s = new Son(); s.test(30); } } class Father{ int a = 10; } class Son extends Father{ int a = 20; public void test(int a){ System.out.println(super.a);//10 System.out.println(this.a);//20 System.out.println(a);//30 } }
2、super.成员方法
在子类对象中访问从父类继承的在子类中仍然可见的成员方法
1)子类没有重写方法
public class Test{ public static void main(String[] args){ Son s = new Son(); s.test(); } } class Father{ public void method(){ System.out.println("aa"); } } class Son extends Father{ public void test(){ method();//aa this.method();//aa super.method();//aa } }
2)子类重写父类的方法
public class Test{ public static void main(String[] args){ Son s = new Son(); s.test(); } } class Father{ public void method(){ System.out.println("aa"); } } class Son extends Father{ public void method(){ System.out.println("bb"); } public void test(){ method();//bb this.method();//bb super.method();//aa } }
this(...) -- 本类的构造方法 super(...) -- 父类的构造方法
super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。
1、修饰类
表示这个类不能被继承,没有子类
final class Eunuch{//太监类 }
2、修饰方法
表示这个方法不能被子类重写
class Father{ public final void method(){ System.out.println("father"); } }
某个变量如果使用final修饰,那么它的值就不能被修改,即常量
final可以修饰成员变量(静态的类变量和非静态的实例变量)和局部变量
如果某个成员变量用final修饰后,没有set方法,并且必须有显式赋值语句,不能使用成员变量默认值
被final修饰的常量名称,一般都有书写规范,所有字母都大写
public class Test{ public static void main(String[] args){ final int MIN_SCORE = 0; final int MAX_SCORE = 100; } } class Chinese{ public static final String COUNTRY = "中华人民共和国"; private final String BLOODTYPE = "A";//显示赋值 private final String CARDID;//如果没有显示赋值,必须保证在 private String name; public Chinese(String cardId, String name) { super(); this.CARDID = cardId; this.name = name; } public Chinese() { super(); CARDID = "000000000000000000";//必须在所有构造器中进行赋值 } public String getName() { return name; } public void setName(String name) { this.name = name; } //final修饰的没有set方法 public static String getCountry() { return COUNTRY; } public String getCardId() { return cardId; } public String getBloodType() { return bloodType; } }