疯狂JAVA讲义学习——基础代码练习——继承extends关键字、this、super、构造器
类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
类的继承格式
继承类型
需要注意的是 Java 不支持多继承,但支持多重继承。
继承的特性
-
子类拥有父类非 private 的属性、方法。
-
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
-
子类可以用自己的方式实现父类的方法。
-
Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
-
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。
构造器
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。
如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
class Base { public double size; public String name; public Base(double size, String name) { this.size = size; this.name = name; } } public class Sub extends Base { public String color; public Sub(double size, String name, String color) { super(size, name); this.color = color; } public static void main(String[] args) { Sub s = new Sub(5.6, "测试对象", "红色"); System.out.println(s.size + "--" + s.name + "--" + s.color); } }
super调用父类的构造器
子类构造器总会调用父类构造器。
如果子类构造器没有显式使用super调用父类构造器;子类构造器默认会调用父类无参数的构造器。
创建一个子类实例时,总会先调用最顶层父类的构造器。
class SuperClass { private int n; SuperClass() { System.out.println("SuperClass()"); } SuperClass(int n) { System.out.println("SuperClass(int n)"); this.n = n; } } class SubClass extends SuperClass { private int n; SubClass() { System.out.println("SubClass"); } public SubClass(int n) { super(300); System.out.println("SubClass(int n):"+n); this.n = n; } } class SubClass2 extends SuperClass { private int n; SubClass2() { super(300); System.out.println("SubClass2"); } public SubClass2(int n) { System.out.println("SubClass2(int n):"+n); this.n = n; } } public class TestSuperSub { public static void main (String args[]) { System.out.println("------SubClass------"); SubClass sc1 = new SubClass(); SubClass sc2 = new SubClass(100); System.out.println("------SubClass2------"); SubClass2 sc3 = new SubClass2(); SubClass2 sc4 = new SubClass2(200); } }
class SuperClass { private int n; SuperClass(){ System.out.println("SuperClass()"); } SuperClass(int n) { System.out.println("SuperClass(int n)"); this.n = n; } } // SubClass 类继承 class SubClass extends SuperClass{ private int n; SubClass(){ // 自动调用父类的无参数构造器 System.out.println("SubClass"); } public SubClass(int n){ super(300); // 调用父类中带有参数的构造器 System.out.println("SubClass(int n):"+n); this.n = n; } } // SubClass2 类继承 class SubClass2 extends SuperClass{ private int n; SubClass2(){ super(300); // 调用父类中带有参数的构造器 System.out.println("SubClass2"); } public SubClass2(int n){ // 自动调用父类的无参数构造器 System.out.println("SubClass2(int n):"+n); this.n = n; } } public class TestSuperSub{ public static void main (String args[]){ System.out.println("------SubClass 类继承------"); SubClass sc1 = new SubClass(); SubClass sc2 = new SubClass(100); System.out.println("------SubClass2 类继承------"); SubClass2 sc3 = new SubClass2(); SubClass2 sc4 = new SubClass2(200); } }
=====================================================
Person p = new Person();
这行代码创建了一个Person实例,也被称之为Person对象,这个Person被赋给p变量;
在这行代码中实际上产生了2个东西:一个是p变量,一个是Person对象;
使用构造器执行初始化
1、构造器最大的用处就是在创建对象时执行初始化,系统会默认的进行初始化。
2、如果程序员没有Java 类提供任何构造器,则系统会为这个类提供一个无参的构造器。
3、一旦程序员提供了自定义的构造器,遇系统不再提供默认的构造器。
=================================================================================
构造器的重载
构造器的重载和方法的重载一样,都是方法名相同,形参列表不相同。
在构造器中可通过this来调用另外一个重载的构造器。
public class ConstructorOverload { public String name; public int count; // 提供无参数的构造器 public ConstructorOverload(){} // 提供带两个参数的构造器, // 对该构造器返回的对象执行初始化 public ConstructorOverload(String name, int count) { this.name = name; this.count = count; } public static void main(String[] args) { // 通过无参数构造器创建ConstructorOverload对象 var oc1 = new ConstructorOverload(); // 通过有参数构造器创建ConstructorOverload对象 var oc2 = new ConstructorOverload( "轻量级Java EE企业应用实战", 300000); System.out.println(oc1.name + " " + oc1.count); System.out.println(oc2.name + " " + oc2.count); } }
public class ConstructorOverload { public String name; public int count; public ConstructorOverload() { } public ConstructorOverload(String name, int count) { this.name = name; this.count = count; } public static void main(String[] args) { ConstructorOverload oc1 = new ConstructorOverload(); ConstructorOverload oc2 = new ConstructorOverload("轻量级Java EE企业应用实战", 300000); System.out.println(oc1.name + " " + oc1.count); System.out.println(oc2.name + " " + oc2.count); } }
==========================================================
public class Apple { public String name; public String color; public double weight;
public Apple(){}
// 两个参数的构造器 public Apple(String name, String color) { this.name = name; this.color = color; }
// 三个参数的构造器 public Apple(String name, String color, double weight) { // 通过this调用另一个重载的构造器的初始化代码 this(name, color);
// 下面this引用该构造器正在初始化的Java对象 this.weight = weight; } }
PS:减少代码复用量,
===========================================================
父类实例的super限定
通过关键字super 来调用父类的方法或属性
class Parent { public String tag = "疯狂Java讲义"; // ① } class Derived extends Parent { // 定义一个私有的tag实例变量来隐藏父类的tag实例变量 private String tag = "轻量级Java EE企业应用实战"; // ② } public class HideTest { public static void main(String[] args) { var d = new Derived(); // 程序不可访问d的私有变量tag,所以下面语句将引起编译错误 // System.out.println(d.tag); // ③ // 将d变量显式地向上转型为Parent后,即可访问tag实例变量 // 程序将输出:“疯狂Java讲义” System.out.println(((Parent) d).tag); // ④ } }
=====================================================
super调用父类的构造器
1、子类构造器总会调用父类构造器。
2、如果子类构造器没有显式使用super调用父类构造器;子类构造器默认会调用父类无参数的构造器。
3、创建一个子类实例时,总会先调用最顶层父类的构造器。
class Base { public double size; public String name; public Base(double size, String name) { this.size = size; this.name = name; } } public class Sub extends Base { public String color; public Sub(double size, String name, String color) { // 通过super调用来调用父类构造器的初始化过程 super(size, name); this.color = color; } public static void main(String[] args) { var s = new Sub(5.6, "测试对象", "红色"); // 输出Sub对象的三个实例变量 System.out.println(s.size + "--" + s.name + "--" + s.color); } }
class Base { public double size; public String name; public Base(double size, String name) { this.size = size; this.name = name; } } public class Sub extends Base { public String color; public Sub(double size, String name, String color) { super(size, name); this.color = color; } public static void main(String[] args) { Sub s = new Sub(5.6, "测试对象", "红色"); System.out.println(s.size + "--" + s.name + "--" + s.color); } }
class Creature { public Creature() { System.out.println("Creature无参数的构造器"); } } class Animal extends Creature { public Animal(String name) { System.out.println("Animal带一个参数的构造器," + "该动物的name为" + name); } public Animal(String name, int age) { // 使用this调用同一个重载的构造器 this(name); System.out.println("Animal带两个参数的构造器," + "其age为" + age); } } public class Wolf extends Animal { public Wolf() { // 显式调用父类有两个参数的构造器 super("灰太狼", 3); System.out.println("Wolf无参数的构造器"); } public static void main(String[] args) { new Wolf(); } }
class Creature { public Creature() { System.out.println("Creature----wu---can"); } } class Animal extends Creature { public Animal(String name) { System.out.println("Animal111111111111111111" + "name-----------" + name); } public Animal(String name, int age) { this(name); System.out.println("Animal2222222222222222222" + "age---------------" + age); } } public class Wolf extends Animal { public Wolf() { super("hui---tai----lang", 3); System.out.println("Wolf----wu----can"); } public static void main(String[] args) { new Wolf(); } }
执行结果:
Creature----wu---can
Animal111111111111111111name-----------hui---tai----lang
Animal2222222222222222222age---------------3
Wolf----wu----can