一、封装
1、封装的概念
封装即对要操作的实体进行隐藏,使原始功能对外不可见,通过其他对外提供的方法间接的操作真实的实体。
2、封装的实现原理
Java语言中为实现对实体的封装,可以对类内的成员进行私有化(private)声明,使其属性和功能对外不可见,然后为其提供对应的访问器,对原始被封装的实体进行操作。访问器有两种:
获取访问器:getXxx();
修改访问器: setXxx();
好处:
将变化隔离;
方便使用;
提高复用性;
提高安全性
3、封装的标准实现:封装通常是对程序变量进行,成员方法也可使用,但是通常意义不大。
二、继承
继承描述的是一种类间关系,通过继承可以减少模型内部结构的重复描述,增强了代码的复用性。
1、实现继承的格式
class 子类名extends 父类名{ }
2、继承的作用
1)子类可以继承父类所有的成员,包括成员变量和成员方法;
2)子类可以添加父类没有的成员;
3)子类可以对父类中已有的成员变量进行重定义;
4)子类可以对父类中已有的成员方法进行重定义,即重写或覆盖。
3、继承的特点
1)在Java中只支持类的单继承和多层继承,但不支持多继承。
因为如果一个类继承多个类,多个类中有相同的方法,子类调用该方法时就不知道该调用哪一个类中的方法了。
2)子类中可以使用super调用父类成员
super用法和this类似,this是谁调用该方法就引用谁,super是调用该方法的对象的父类对象。
4、重写
重写只发生在继承关系中,描述的是子类实例方法与父类实例方法的关系,指子类对父类中已有的实例方法进行重新定义。
重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型。
子类的方法返回值类型可以是父类方法返回值类型的子类。
如果在子类中想调用父类中的那个被重写的方法,我们可以用super.方法的格式。
如果直接调用方法,是在当前子类中先查找,如果子类有会调用子类的。使用super形式只在父类中查找,子类有没有都不调用。
重写方法时,不能使用比父类中被重写的方法更严格的访问权限。
因为有可能将子类对象当做父类对象来使用,那么能获取到的父类对象中的方法在子类中必须都能获取到。
重写方法时,不能比父类抛出更多的异常。
子类只能比父类强,不能比父类弱。
重载(Overload)和重写(Override)的区别:
重载是方法名相同,参数列表不同,和返回值类型无关。
重写是方法名、参数列表、返回值类型全相同。
注意:
静态方法的覆盖称为子类隐藏了父类的静态方法,而不是重写了父类方法
父类的私有方法,子类是无法继承的,因此父类私有方法不能被重写
实例方法在重写时不能添加static修饰符,静态方法被重新定义时不能定义为非静态的方法
5、向上转型
把一个子类当做父类来用是可以的,因为父类有的子类都有
把一个父类当做子类来用就不可以了,因为子类有的父类不一定有
可以定义一个父类类型的变量来记住子类对象,这在程序中称之为向上转型
6、强制类型转换
把一个子类当做父类来用的时候,不能调用子类特有方法。
因为编译时编译器会做语法检查,看到变量是父类类型那么就会到父类中查找是否有该方法,没有则报错。这种情况下,就需要强制类型转换,
将父类类型强转成子类类型。以(子类名)变量名形式进行强制类型转换
强制类型转换时,无论类型是否匹配编译都不会报错,但如果类型不匹配运行会报错,我们可以使用instanceof进行判断,编译时预知错误。
在子类当做父类来用时,不能调用特有方法,如果一定要调用,就需要强制类型转换回子类。在做转换时最好instanceof判断一下类型是否匹配。
7、子类当作父类使用时注意事项
当我们在调用某个类的一个方法时,此方法声明需要一个父类对象,这时我们可以将一个子类对象作为实参传递过去,注意此时方法定义的形参为
父类,在方法中使用父类变量调用方法时,其实是调用子类的方法。
在把子类当做父类来用时,使用父类变量访问方法,访问的是子类的方法,因为虚拟机会找到变量引用的地址,根据这个地址来访问方法,这叫动
态分配。这种机制没有被使用到类的成员变量上,如果用父类变量访问属性,那么会直接找到父类的属性,不会看地址是哪个对象。
8、继承应用细节
1)子类不继承父类私有成员
父类中私有成员对外不可见,子类对象中无法访问这些成员。
2)构造函数不被继承
构造函数通常用来初始化类的成员变量,父类和子类的成员变量不同,初始化方式也不同,构造函数的名字也不同。
3)只支持单继承
如果一个类继承多个类,那么多个类中有相同的方法,调用时会引起歧义。
知识点:final关键字
继承的出现,打破了对象的封装性,使得子类可以随意复写父类中的功能。这也是继承的一大弊端。那么怎么解决这个问题呢?这里就引出了一个新的关键字——final(最终)。
final作为一个修饰符。具有以下特点:
1、可以修饰类、函数、变量。
2、被final修饰的类不可以被继承。这样就可以避免被继承、被子类复写功能。
3、被final修饰的方法不可以被复写。
4、被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,又可以修饰局部变量。
当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成,单词间通过_连接。
5、内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。
9、继承中的修饰符限制
Protected
父类中可以通过为成员添加protected访问控制修饰符,限定哪些父类成员仅供子类继承
private
父类中可以通过为成员添加private访问控制修饰符,限定哪些父类成员不被子类继承
public
公共的成员不受任何约束,可以被继承
二、继承
1.集成的概念及作用
(1)把很多类的相同特征和行为进行抽取,用一个类来描述。让多个类和这个类产生一个关系。
这样的话,多个类就可以省略很多代码。这个关系就是继承。java中用extends关键字表示。
(2)继承的体系结构
A:多个具体的对象,不断的向上抽取共享的内容,最终形成了一个体系。这个体系叫做继承体系。
B:继承体系的学习和使用原则
**学习顶层的内容。因为他是整个体系的共性内容。
**创建子类使用。也就是使用底层的具体对象。
(3)继承的特点:
A:java中只能单继承,没有多继承。
B:java可以有多重(层)继承。
(4)继承的好处:
继承的出现提高了代码的复用性。
继承的出现让类与类之间产生了关系,提供了多态的前提。
2.子父类中的成员关系
A:成员变量
在子类方法中使用一个变量时:
首先,在方法的局部变量中找这个变量,有则使用。
否则,在本类中找成员变量,有则使用。
否则,在父类中找成员变量,有则使用。
否则,报错。
B:成员方法
用子类对象使用一个方法时。
首先,在子类中找这个方法,有则使用。
否则,在父类中找这个方法,有则使用。
否则,报错。
3.重写和重载的区别
重载:在同一类中。方法名相同,参数列表不同。重载可以改变返回类型。
重写:在不同类中(子父类中)。
方法声明相同(返回类型,方法名,参数列表均相同)。
重写需要注意:
**子类方法的访问权限要大于等于父类方法的访问权限。
**静态只能重写静态。但是这种情况一般不会出现。
构造方法
**子类的实例化过程
***子类创建对象时,会先去创建父类的对象。
默认是去调用父类的无参构造方法。
***子类构造方法中,第一行默认是super()
***为什么子类中第一行会默认有super()
因为他继承父类的成员使用,使用前这些成员必须初始化,
而他们是父类的成员,所以,必须通过父类进行初始化。
所以,会先创建一个父类的对象。
**当父类没有无参构造方法时
必须使用this或者super调用其他的构造方法。
(6)this和super的区别
this:代表本类对象的引用。
super:代表父类的存储空间。
4、final关键字
(1)最终的意思,可以用于修饰类,方法,变量。
(2)final修饰的类不能被继承。
final修饰的方法不能被重写。
final修饰的变量是一个常量。只能被赋值一次。
内部类只能访问被final修饰的局部变量。
三、抽象类
1.、抽象类概念特点
(1)多个类有相同的方法声明,但是方法体不一样。这个时候,我们考虑把方法声明进行抽取。
让子类继承后,自己去实现方法体。没有方法体的方法,我们需要用抽象标志下。
抽象的关键字是:abstract。
(2)抽象类:
该方法称为抽象方法,包含抽象方法的类就是抽象类。
(3)抽象类的特点:
A:抽象类和抽象方法都要用abstract进行修饰
B:抽象类不能被实例化
C:抽象类中不一定有抽象方法,但是,有抽象方法的类一定是抽象类。
(4)抽象类中数据的特点
A:成员变量
抽象类中可以有变量,也可以有常量。
B:成员方法
抽象类中可以有抽象方法,也可以有非抽象方法。
C:构造方法
抽象类是一个类,所以,它有构造方法。
虽然本身不能实例化。但是可以给子类实例化使用。
2.抽象类中的问题
A:抽象类中是否有构造方法?能不能被实例化?如果不能,为什么有构造方法?
抽象类有构造方法。
抽象类不能被实例化。
抽象类中的构造方法供子类实例化调用。
B:抽象关键字abstract不可以和哪些关键字共存?
**private:
私有内容子类继承不到,所以,不能重写。
但是abstract修饰的方法,要求被重写。两者冲突。
**final
final修饰的方法不能被重写。
而abstract修饰的方法,要求被重写。两者冲突。
**static
假如一个抽象方法能通过static修饰,那么这个方法,就可以直接通过类名调用。 而抽象方法是没有方法体的,这样的调用无意义。所以,不能用static修饰。
C:抽象类中可不可以没有抽象方法?如果可以,这样的类有什么用吗?
抽象类可以没有抽象方法。
抽象类中没有抽象方法的作用,只是为了不让别的类建立该抽象类对象。这个在awt中有体现。
四、接口
1、概述
接口,可以被认为是一个特殊的抽象类。当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。接口使用interface来表示,子类中用implements实现。格式为:
interface 接口名{}
子类名implements接口名{}
格式特点:
1)接口中常见定义:常量,抽象方法。
2)接口中的成员都有固定修饰符。
常量:publicstatic final
方法:publicabstract
3)接口中的成员都是public的。
在使用中,常量可以不写publicstatic final,方法可以不写publicabstract,编译时Java会自动添加这些修饰符,因为这是固定的格式修饰符。但为了方便阅读,通常我们都写上。
2、特点
1)接口是对外暴露的规则。
2)接口是程序的功能扩展。
3)接口的出现降低耦合性。
4)接口可以用来多实现。这也是对多继承不支持的转换形式。java支持多实现。
5)类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。
6) 接口与接口之间可以有继承关系。而且可以多继承。
注:1)接口不可以创建对象的,因为有抽象方法。需要被子类实现(implements),子类对接口中的抽象方法全都覆盖后,子类才可以实例化。否则子 类是一个抽象类。
2)实现多个接口时,接口中不可以有返回不同类型的同名抽象函数。这样子类实现时将不能复写。
3、接口的合并
使用关键字extends
interface 接口名 extends 接口1,接口2....{
}
接口合并后最终得到一个接口,这个接口包含所有接口中的成员。
接口合并冲突:
变量:接口合并时,如果多个接口中定义了相同的变量名,在合并时不会引起编译报错
在使用时,如果使用接口名调用常量,也不会因此报错
只有在运行程序时,使用接口的实现类调用有名称冲突的常量时才会因此编译报错
方法:当两个接口中定义的方法,具有相同的名称,参数,返回值类型时,这两个方法 只需要实现一次就行了
如果两个接口中定义的方法,具有相同的名称,参数,不同的返回值类型
这个时候只能说定义时没有对具体的方法进行确认,同一件事使用了两种声明格式
接口的实例程序:
interface Biology{
void eat();
void breath();
}
//创建接口实现类,因为全部实现接口中的方法,所以只能声明为抽象类
abstract class Animal implements Biology{
//实现接口中的抽象方法
public void breath(){
System.out.println("用鼻子呼吸");
}
}
//创建接口实现类的子类,
class Cat extends Animal{
//复写父类类中的抽象方法
public void eat(){
System.out.println("猫吃鱼");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃肉");
}
}
class Demo{
public static void main(String[] args){
Biology b = new Cat();
b.breath();
b.eat();
}
}
4、接口与抽象类
共性:都是不断向上抽取出来的抽象的概念。
区别:
1)抽象类体现继承关系,一个类只能单继承。
接口体现实现关系,一个类可以多实现。同时接口与接口之间有继承关系。
2)抽象类是继承,是 "is a "关系。
接口是实现,是"like a"关系。
3)抽象类中可以定义非抽象方法,供子类直接使用。
接口的方法都是抽象,接口中的成员都有固定修饰符。
4)抽象类中可以私有变量或方法。
接口中的常量和方法都是public修饰的权限。