继承 extends
多个类有共同的成员变量和成员方法,可以抽取到另外一个类(父类),再让多个类去继承这个父类,这些类就可以获取到父类中的成员。
public class ExtendsDemo {
public static void main(String[] args) {
Dota dead = new Dota();
dead.start(); // 启动游戏
Lol l = new Lol();
l.start(); // 启动游戏
}
}
class Game {
String name;
double version;
String agent;
public void start() {
System.out.println("启动游戏");
}
public void exit() {
System.out.println("退出游戏");
}
}
class Dota extends Game {} // Dota继承Game类
class Lol extends Game {} // Lol继承Game类
Java中继承的特点
- 只支持单继承,不支持多继承(即只可以有一个父类)
class sub extends Demo{} // ok
class sub extends Demo1,Demo2{} // error
- 支持多层继承(继承体系)
class A{}
class B extends A{}
class C extends B{}
Java中成员变量继承的特点
- 子类中只能获取父类中非private的成员变量
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName();
c.sayAge();
}
}
class Dad {
String name = "dad";
private int age = 40;
}
class Child extends Dad {
public void sayName () {
System.out.println(name);
}
public void sayAge () {
System.out.println(age);
}
}
上述例子中,提示Dad.age
这个字段不可见。所以子类中只能获取父类中非private的成员变量
- 如果子类和父类中的成员变量名字一样,那么遵循就近原则
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName(); // child 就近原则 输出子类中的成员属性
}
}
class Dad {
String name = "dad";
}
class Child extends Dad {
String name = "child";
public void sayName () {
System.out.println(name);
}
}
- 对于上述的就近原则,可以通过
super
关键字来获取父类中的成员变量和方法
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName(); // dad
}
}
class Dad {
String name = "dad";
}
class Child extends Dad {
String name = "child";
public void sayName () {
System.out.println(super.name); // super.name 获取父类中的成员
}
}
- 当涉及到局部变量和成员变量重名时,得使用
this
来获取当前类中的成员
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName();
}
}
class Dad {
String name = "dad";
}
class Child extends Dad {
String name = "child";
public void sayName () {
String name = "testName";
System.out.println("父类:" + super.name); // super.name 获取父类中的成员
System.out.println("当前类:" + this.name); // this.name 获取当前类中的成员
System.out.println("局部变量:" + name); // name 获取当前作用域中的局部变量
}
}
Java中成员方法继承的特点
方法继承支持重写(不是重载),子类中的方法和父类中。的方法完全一致时,可以在子类中重写这个方法。子类的对象调用时调用的是子类重写的方法
关于重写有一些注意点:
- 在子类重写的方法中,可以使用
super.methodName()
来执行父类中的方法,这么写既可以使用父类的功能,也可以追加子类的逻辑。 - 重写前可以添加注解
@Override
加强规范 - 不能重写父类中private的成员变量,子类中方法的权限(如:public)必须要比父类中的权限等级高。
定义方法的时候,可以不写权限修饰(比如: public), 那么就代表默认权限(如void show() {}
)
Java中构造方法的执行顺序
- 如果子类的构造方法中的第一行代码中没有调用父类或者子类的构造方法时,那么会默认调用父类的无参构造方法
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();// Super Constructor---no Args Sub Constructor---no Args
}
}
class Dad {
public Dad () {
System.out.println("Super Constructor---no Args");
}
public Dad (int num) {
System.out.println("Super Constructor---have Args");
}
}
class Child extends Dad {
public Child () {
System.out.println("Sub Constructor---no Args"); // 第一行没有调用父类构造方法,默认调用父类无参构造
}
public Child (int num) {
System.out.println("Sub Constructor---have Args");
- 可以使用
super()
来在子类的构造方法的第一行中调用父类的构造方法
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();// Super Constructor---have Args Sub Constructor---no Args
}
}
class Dad {
public Dad () {
System.out.println("Super Constructor---no Args");
}
public Dad (int num) {
System.out.println("Super Constructor---have Args");
}
}
class Child extends Dad {
public Child () {
super(1); // 调用了父类的构造方法
System.out.println("Sub Constructor---no Args");
}
public Child (int num) {
System.out.println("Sub Constructor---have Args");
}
}
- 不管有没有参数,父类的构造方法总是优先于子类的构造方法被执行
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();// Super Constructor---no Args Sub Constructor---have Args Sub Constructor---no Args
}
}
class Dad {
public Dad () {
System.out.println("Super Constructor---no Args");
}
public Dad (int num) {
System.out.println("Super Constructor---have Args");
}
}
class Child extends Dad {
public Child () {
this(1); // 调用了子类的有参构造方法
System.out.println("Sub Constructor---no Args");
}
public Child (int num) {
System.out.println("Sub Constructor---have Args");//有参构造第一行中没调用父类的构造方法,于是默认调用父类的无参构造
}
}
this 和 super的区别
this: 当前对象的引用
super:子类对象的父类引用
在构造方法中的第一行中,直接写this()
或者super()
就是默认调用构造方法。
如果子类中没有制定的成员属性,而只有父类中有的时候,调用this.xxx
就是访问的父类的成员属性
继承的优缺点
优点:
- 提高代码的复用性和可维护性
缺点:
- 类的耦合性增强了
- 开发的原则:高内聚低耦合
- 内聚:就是自己完成某件事的能力
- 耦合:类和类的关系
抽象类
abstract: 关键字,用于修饰方法和类
抽象方法:不同类的方法是相似的,但是具体逻辑不太一样,只能抽取声明,没有具体的方法体。 即没有方法体的方法就是抽象方法,抽象方法只能在抽象类中使用。
抽象类: 有抽象方法的类必须是抽象类。
如果有其他类继承了抽象类,那必须要重写其中的抽象方法,或者这个类必须也是抽象类。
public class ExtendsDemo {
public static void main(String[] args) {}
}
abstract class Animal { // 有抽象方法的类必须是抽象类
public abstract void eat(); // abstract修饰的是方法是抽象方法 没有方法体
}
class Cat extends Animal { // 如果一个类继承了抽象类,而且同时还不也是一个抽象类的话,那么必须要重写抽象类中的抽象方法
@Override
public void eat() { // 重写抽象类中的抽象方法
System.out.println("猫吃鱼");
}
}
abstract class Dog extends Animal {} // 抽象类的Dog 本身也是一个抽象类 就不需要重写抽象方法了
抽象类的特点:
- 抽象方法只能在抽象类中
- 抽象类不能实例化(不能new)
- 抽象类可以有非抽象类(非抽象类被继承不需要强制重写)
抽象类的成员的特点:
- 成员变量
- 可以有成员变量
- 可以有常量(被final修饰)
- 成员方法
- 可以有抽象方法和非抽象方法
- 构造方法
- 可以有构造方法(但是不能创建对象),因为需要对类中的成员变量进行初始化
final: 修饰类、成员变量、成员方法,修饰了之后不能被继承
抽象类的细节:
- abstract 不可以和 final, private 共存
- 可以有构造函数(因为有成员变量,要初始化成员变量,同时还要被继承,子类继承父类也要调用父类的构造函数)
- 内部也可以没有抽象方法(当不想让这个不可以类实例化的时候,当然也可以使用private构造函数来达到一样的效果)