面向对象
面向对象
封装
- 是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
- 提高了代码的复用性,安全性
通过对象去给成员变量赋值,可以赋值一些非法的数据。
public class Student(){
public int age;
}
//main
Student s = new Student();
s.age = -1; //这是不合理的
所以我们将属性封装起来,并让外界通过我指定的通道访问和修改我的属性
用private修饰属性
private关键字:
-
是一个权限修饰符。
-
可以修饰成员(成员变量和成员方法)
-
被private修饰的成员只在本类中才能访问
public class Student(){ private int age; public int getAge(){ return this.age; } public void setAge(int age){ if(age>0&&age<120){ this.age = age; }else{ system.out.println("输入错误"); } } } //main Student s = new Student(); s.age = -1; //输入错误
继承
概述
- 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
- 通过extends关键字可以实现类与类的继承
class 子类名 extends 父类名 {} - 单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
- 有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。
好处
-
提高了代码的复用性
- 多个类相同的成员可以放到同一个类中
-
提高了代码的维护性
- 如果功能的代码需要修改,修改一处即可
-
让类与类之间产生了关系,是多态的前提
其实这也是继承的一个弊端:类的耦合性很强开发的原则:低耦合,高内聚。 耦合:类与类的关系 内聚:就是自己完成某件事情的能力
java继承的注意
-
java只支持单继承,不支持多继承。
一个类只能有一个父类,不可以有多个父类。class Son extends Futher{} //ok class Son extends Futher,Mother{}//error
-
Java支持多层继承(继承体系)
class GrandFuther{} class Futher extends GrandFuther{} class Son extends Futher{}
-
子类只能继承父类所有非私有的成员(成员方法和成员变量)
-
子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
-
不要为了部分功能而去继承
class A { public void method1(){} public void method2(){} } class B { public void method2(){} public void method3(){} } //我们发现B类中出现了和A类一样的method2()方法,所以,我们就用继承来体现 class B extends A { public void method3(){} } 这样其实不好,因为这样你不但有了method2(),还多了method1()。 有可能method1()不是你想要的。 什么时候考虑使用继承呢? 继承其实体现的是一种关系:"is a"。 Person Student Teacher Student是Person的一种
-
直接调用属性名时,同名属性的查找顺序(就近原则)
子类方法局部->子类成员->父类成员->找不到报错(单层继承情况下)
同: 属性 -> this.属性 -> super.属性
this&super
不能在static中使用,static属于类的
-
调用成员变量
- this.成员变量 调用本类的成员变量
- super.成员变量 调用父类的成员变量
-
调用构造方法
- this(...) 调用本类的构造方法
- super(...) 调用父类的构造方法
-
调用成员方法
- this.成员方法 调用本类的成员方法
- super.成员方法 调用父类的成员方法
构造函数的关系
子类不继承父类的构造函数,可以用super调用
子类中所有的构造方法再不写super的情况下默认都会访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据。
所以,子类初始化之前,一定要先完成父类数据的初始化。
注意:子类每一个构造方法的第一条语句默认都是:super(),即使删除也有;
当子类没有构造函数的时候,系统默认提供一个无参构造方法
public class Fu { //父类,提供了有参构造,所有系统不会提供一个无参构造,即没有无参构造
private String str = "name";
private int i = 1;
public Fu(String str, int i) {
this.str = str;
this.i = i;
}
}
//--------------------
public class Zi extends Fu{//子类没有提供构造函数,系统自动提供一个无参构造,但是无参构造第一句默认super(),父类没有,报错
//error:Implicit super constructor Fu() is undefined. Must explicitly invoke another constructor
//隐式的父类构造函数fu()是未定义的。必须显式调用另一个构造函数
}
//--------------------
public class Zi extends Fu{//子类也无法提供无参构造
public Zi() {
//error:Implicit super constructor Fu() is undefined. Must explicitly invoke another constructor
//隐式的父类构造函数fu()是未定义的。必须显式调用另一个构造函数
}
}
- 子类通过super去显示调用父类其他的带参的构造方法
- 子类通过this去调用本类的其他构造方法
- 本类其他构造也必须首先访问了父类构造
一定要注意:
super(…)或者this(….)必须出现在第一条语句
否则,就会有父类数据的多次初始化
所以一般建议任何类都提供无参构造
继承中的方法
子类与父类的方声明不一样,一般情况
- 首先在子类中找
- 然后在父类中找
- 如果还是没有就报错。(不考虑多重继承)
重写(Override)
子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖
- 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法
注意:
-
父类中私有方法不能被重写(子类写了相当于自己的创建方法,不算重写)
-
子类重写父类方法时,访问权限不能更低
-
父类静态方法,子类也必须通过静态方法进行重写。(不算是重写,但现象是这样)
public class Fu { public static void pri() { System.out.println("a"); } } //---------------------- public class Zi extends Fu{ //This instance method cannot override the static method from Fu public void pri() { System.out.println("b"); } }
多态
有继承关系
有方法重写(没有方法重写的多态将没有意义)
有父类引用指向子类对象
多态中的成员访问特点:
不能调用调用子类特有的属性和方法
- 成员变量
- 编译看左边,运行看左边。
- 构造方法
- 创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
- 成员方法
- 编译看左边,运行看右边。
- 静态方法
- 编译看左边,运行看左边。(静态和类相关,算不上重写,所以,访问还是左边的)
class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("function Fu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//要有父类引用指向子类对象。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//System.out.println(f.num2); //num2 cannot be resolved or is not a field(Fu中找不到num2)
f.show();
//f.method(); //The method method() is undefined for the type Fu(Fu中找不到method)
f.function();
}
}
好处与弊端
- 多态的好处:
- 提高了代码的维护性(继承保证)
- 提高了代码的扩展性(由多态保证)
- 多态的弊端
- 不能调用调用子类特有的属性和方法
向上向下转型
向上转型
Fu f = new Zi();
向下转型:把父类的引用强转为子类的引用
Zi z = (Zi)f;
多态继承中的内存图解
B0iOfer.png多态中的对象变化内存图解
- 不可以访问子类的方法
- 不可以强转成其他子类(ClassCastException)
//ClassCastException
DuoTaiDemo f1 = new Zi();
DuoTaiDemo f2 = new DuoTaiDemo();
DuoTaiDemo f3 = (Zi2)f1;
DuoTaiDemo f4 = (Zi)f2;