黑马程序员-继承

-----------android培训java培训、java学习型技术博客、期待与您交流! ------------


一、继承的概念


多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,让多个类和这个类产生一个关系。这样的话,多个类无需再定义这些属性和行为,多个类就可以省略很多代码。这个关系就是继承。java中用extends关键字表示。

多个类可以称为子类,单独这个类称为父类或者超类。
子类可以直接访问父类中的非私有的属性和行为。


二、继承的特点


(1)java中只能单继承,没有多继承。


     原因:因为多继承容易带来安全隐患:当多个父类中定义了相同功能,并且功能内容不同时,子类对象不确定要运行哪一个。

     但是java保留这种机制,并用另一种体现形式来完成表示——多实现。


(2)java可以有多重(层)继承。


     多个具体的对象,不断的向上抽取共享的内容,这样就出现了继承体系。


三、继承的好处



(1)提高代码复用性,定义在父类中的成员(变量和方法),可以被子类重复使用;(次要好处)

(2)让类与类之间产生关系,这样就会有多态的特性。使得应用起来更方便。(主要好处)

定义继承需要注意:

1)不要仅为了获取其他类中某个功能而去继承。组合技术通常用于想在新类中使用其他现有类的功能而非它的接口这种情形。

2)类与类之间的所属( " is a " )关系,即xx1是xx2的一种,是用继承来表达的;而包含(“has a”)关系则是用组合来表达的。


四、继承与组合


都是为了提高代码复用性而生的。


1、定义


组合:在新的类中产生现有外部类的对象,作为新类的成员对象(字段)。

继承:采用现有类的形式并在其内部添加新代码,创建新类。


2、什么时候用


组合:想在新类中使用其他现有类的功能而非它的接口。

继承:当需要从新类向基类进行向上转型,用继承来表示“新类是现有类的一种类型”。


3、优先级


优先选择使用组合,只在确实必要时才使用继承(什么时候必要?如果必须向上转型,则继承是必要的)。

原因:组合更具灵活性。


4、组合代码示例:


//: reusing/Car.java
// Composition with public objects.

class Engine {
	public void start() {
	}

	public void rev() {
	}

	public void stop() {
	}
}

class Wheel {
	public void inflate(int psi) {
	}
}

class Window {
	public void rollup() {
	}

	public void rolldown() {
	}
}

class Door {
	public Window window = new Window();

	public void open() {
	}

	public void close() {
	}
}

public class Car {
	public Engine engine = new Engine();
	public Wheel[] wheel = new Wheel[4];
	public Door left = new Door(), right = new Door(); // 2-door

	public Car() {
		for (int i = 0; i < 4; i++)
			wheel[i] = new Wheel();
	}

	public static void main(String[] args) {
		Car car = new Car();
		car.left.window.rollup();
		car.wheel[0].inflate(72);
	}
} // /:~


五、super关键字

super和this的用法相像

1、含义

this代表本类对象的引用,super代表父类的内存空间的标识(位置也在本类对象中)。

2、什么时候用

当子父类出现同名成员时,可以用super进行区分;

子类要调用父类构造函数时,可以使用super语句。

3、代码示例:

class Person {
	String name;
	int age;

	Person() {
	}

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
} // 父类的构造方法

class Student extends Person {

	String school;// 子类构造方法

	public Student() {
		super("张三", 25);// 调用父类中的构造方法
	}
}

public class TestStudentDemo {
	
	public static void main(String[] args) {

		Student s = new Student();

		s.school = "北京";

		System.out.println("姓名:" + s.name + ",年龄:" + s.age + ",学校:" + s.school);

	}
}

六、子父类中的成员关系


1、成员变量


在子类方法中使用一个变量时:
首先,在方法的局部变量中找这个变量,有则使用。
否则,在本类中找成员变量,有则使用。
否则,在父类中找成员变量,有则使用。
否则,报错。

2、成员方法


用子类对象使用一个方法时。
首先,在子类中找这个方法,有则使用。
否则,在父类中找这个方法,有则使用。
否则,报错。

七、覆盖(重写)


1、定义:


       当 子类中出现与父类一模一样的方法时, 会出现覆盖操作,也称为重写或者复写(override)。

2、覆盖注意事项:


(1)子类覆盖父类时,必须要保证覆盖方法的权限大于等于被覆盖的方法的权限.
(2)覆盖方法有静态修饰时,静态只能覆盖静态。
(3)父类中的私有方法不可以被覆盖。
    原理:覆盖只有在某方法是基类的接口的一部分时才会出现。即,必须能将一个对象向上转型为它的基本类型并调用相同的方法。如果某方法为private,它就不是基类的接口的一部分。它仅是一些隐藏于类中的程序代码,只不过是具有相同的名称而已。

3、覆盖的应用:


       子类继承父类,沿袭了父类的功能到子类中。但是子类虽具备该功能,但是功能的内容和父类不一致,这时没有必要定义新功能,而是使用覆盖特性。这样,即沿袭了父类的功能,又定义了子类特有的内容。

4、代码示例:


class Father
{  
    int num = 3;  
    void show()  
    {  
        System.out.println(num);  
    }  
}  
  
class Son extends Father  
{  
    int num = 5;  
    //复写父类函数  
    void show()  
    {  
        System.out.println(num);//this引用,此处省略this,结果是5  
        System.out.println(super.num);//super引用,结果是3.  
    }  
}  
  
class Demo  
{  
    public static void main(String [] args)  
    {  
        Son s = new Son();  
        s.show();  
    } 
}


5、重写和重载的区别


(1)重载:在同一类中。方法名相同,参数列表必须不同。 返回值类型可以相同 也可以不相同,无法以返回型别作为重载函数的区分标准。
(2)重写:在不同类中(子父类中)。方法声明相同(方法名,参数列表,返回类型均相同)。

6、@Override注解


(1)作用:
可以防止你在不想重载时而意外的进行了重载。
(2)用法
当你想要覆盖某个方法时,可以选择添加该注解,在你不留心重载而并非覆盖了该方法时,编译器就会生成一条错误信息。

八、继承与初始化(子父类中的构造函数


1、规律:


在对子类对象进行初始化时,父类的构造函数也会运行。那是因为在子类的所有构造函数中的第一行,默认有一条隐式的语句。就是 super( );也就说子类的构造函数默认都会访问父类中空参数的构造函数。


2、为什么子类的构造函数都要去默认访问父类的构造函数呢?


因为子类继承了父类,可以访问父类中的已有的一些属性。 在子类进行实例化的时候必须要为父类中的属性分配空间,并要进行初始化,所以必须要访问一次父类的构造函数,看看父类是如何对其属性进行初始化的。所以子类要实例化对象时,必须要先看父类的初始化过程。

3、结论:


父类的构造函数,既可以给本类对象初始化,也可以给子类对象初始化。

4、注意:


如果父类中没有空参数的构造函数,子类的构造函数中必须手动用super来指定要访问的父类中的构造函数,或者用this来指定访问本类中的构造函数。
this和super调用构造函数只能定义在构造函数的第一行,不能同时出现。为什么都定义在第一行啊?因为初始化的动作要先执行。 

5、代码示例:


// The full process of initialization.
class Insect {
	private int i = 9;
	protected int j;

	Insect() {
		System.out.println("i = " + i + ", j = " + j);
		j = 39;
	}

	private static int x1 = printInit("static Insect.x1 initialized");

	static int printInit(String s) {
		System.out.println(s);
		return 47;
	}
}

public class Beetle extends Insect {
	private int k = printInit("Beetle.k initialized");

	public Beetle() {
		System.out.println("k = " + k);
		System.out.println("j = " + j);
	}

	private static int x2 = printInit("static Beetle.x2 initialized");

	public static void main(String[] args) {
		System.out.println("Beetle constructor");
		Beetle b = new Beetle();
	}
} 
/*打印结果
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 47
j = 39
*/// :~

九、final 


1、继承弊端:打破了封装性。


      解决方式:关键字final ,最终的。

2、用法


(1)最终的意思,可以用于修饰类,方法,变量。
(2)final修饰的类不能被继承。(为了避免被继承,被子类复写功能。维护其封装性)
(3)final修饰的方法不能被重写。(只保护不能被复写的方法)
(4)final修饰的变量是一个常量。只能被赋值一次。(既可以修饰成员变量,又可以修饰局部变量。)
(5)内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。

3、final和private的区别:


(1)final修饰的类可以访问
     private修饰的类不可以访问(其实把类私有化是没有意义的)
(2)final修饰的方法不可以被子类重写
     private修饰的方法表面上看是可以被子类重写的,其实不可以,子类是看不到父类的私有方法的
(3)final修饰的变量只能在显示初始化或者构造函数初始化的时候赋值一次,以后不允许更改
     private修饰的变量,也不允许直接被子类或一个包中的其它类访问或修改,但是他可以通过get和set方法对其改值和取值

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值