-----------android培训、java培训、java学习型技术博客、期待与您交流! ------------
一、继承的概念
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,让多个类和这个类产生一个关系。这样的话,多个类无需再定义这些属性和行为,多个类就可以省略很多代码。这个关系就是继承。java中用extends关键字表示。
多个类可以称为子类,单独这个类称为父类或者超类。
子类可以直接访问父类中的非私有的属性和行为。
二、继承的特点
(1)java中只能单继承,没有多继承。
但是java保留这种机制,并用另一种体现形式来完成表示——多实现。
(2)java可以有多重(层)继承。
多个具体的对象,不断的向上抽取共享的内容,这样就出现了继承体系。
三、继承的好处
(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、定义:
2、覆盖注意事项:
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、重写和重载的区别
6、@Override注解
可以防止你在不想重载时而意外的进行了重载。
当你想要覆盖某个方法时,可以选择添加该注解,在你不留心重载而并非覆盖了该方法时,编译器就会生成一条错误信息。
八、继承与初始化(子父类中的构造函数)
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、继承弊端:打破了封装性。
2、用法
(2)final修饰的类不能被继承。(为了避免被继承,被子类复写功能。维护其封装性)
(3)final修饰的方法不能被重写。(只保护不能被复写的方法)
(4)final修饰的变量是一个常量。只能被赋值一次。(既可以修饰成员变量,又可以修饰局部变量。)
(5)内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。
3、final和private的区别:
private修饰的类不可以访问(其实把类私有化是没有意义的)
(2)final修饰的方法不可以被子类重写
private修饰的方法表面上看是可以被子类重写的,其实不可以,子类是看不到父类的私有方法的
private修饰的变量,也不允许直接被子类或一个包中的其它类访问或修改,但是他可以通过get和set方法对其改值和取值