类的继承格式
在 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