继承
inheritance
子类 父类
子类可以从父类继承属性和方法
子类可以提供自己单独的属性和方法
封装
/
隐藏
encapsulation
对外隐藏某些属性和方法
对外公开某些属性和方法
多态
polymorphism
为了适应需求的多种变化,使代码变得更加通用!
面向过程只有封装性(功能的封装,而没有数据的封装),没有继承和多态
1. 隐藏/封装(encapsulation)
为什么需要封装 ?封装的作用和含义?
我要看电视,只需要按一下开关和换台就可以了。有必要了解电视机内部的结构吗?有必要
碰 碰显像管吗?
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩性、
可维护性。
我们程序设计要追求“高内聚,低耦合”。
高内聚 :就是类的内部数据操作细节自己完成,不允许外部干涉;
低耦合 :仅暴露少量的方法给外部使用。
使用访问控制符,实现封装
成员(成员变量或成员方法)访问权限共有四种:
public 公共的
可以被项目中所有的类访问。(项目可见性)
protected 受保护的
可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包
以及不同包中的子类)访问
default/friendly
默认的
/
友好的(包可见性)
被这个类本身访问;被同一个包中的类访问。
private 私有的
只能被这个类本身访问。(类可见性)
类的访问权限只有两种
public 公共的
可被同一项目中所有的类访问。 (必须与文件名同名)
default/friendly
默认的
/
友好的
可被同一个包中的类访问
![](https://img-blog.csdnimg.cn/fd5ab742a2f243299bfd1c240637099c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YCG6L2u5Zue,size_20,color_FFFFFF,t_70,g_se,x_16)
封装要点:
类的属性的处理
:
一般使用private. (
除非本属性确定会让子类继承
)
提供相应的get/set
方法来访问相关属性
.
这些方法通常是
public
,从而提供对属性的读取
操作。 (注意:boolean
变量的
get
方法是用:
is
开头
!
)
一些只用于本类的辅助性方法可以用
private
希望其他类调用的方法用
public
2.继承
类是对对象的抽象,继承是对某一批类的抽象,从而实现对现实世界更好的建模。
提高代码的复用性!
extands
的意思是“扩展”。子类是父类的扩展
不同的叫法:超类、父类、基类、子类、派生类
![](https://img-blog.csdnimg.cn/dab31f30612345a997d8ed2ffc4c540e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YCG6L2u5Zue,size_20,color_FFFFFF,t_70,g_se,x_16)
继承的好处
通过继承可以简化类的定义,实现代码的重用
子类继承父类的成员变量和成员方法,但不继承父类的构造方法
java
中只有单继承 ,没有像
c++
那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难
于维护。就像我们现实中,如果你有多个父母亲,那是一个多么混乱的世界啊。多继承,就是为了
实现代码的复用性,却引入了复杂性,使得系统类之间的关系混乱。
java
中的多继承,可以通过接口来实现
如果定义一个类时,没有调用
extends
,则它的父类是:
java.lang.Object
。
语法规则,只要在子类加上extends关键字继承相应的父类就可以了:
![](https://img-blog.csdnimg.cn/faf92e8195c443fe88bf7ad349aacaaa.png)
方法的重写(override)
在子类中可以根据需要对从基类中继承来的方法进行重写。
重写方法必须和被重写方法具有相同方法名称、参数列表和返回类型。
重写方法不能使用比被重写方法更严格的访问权限。(由于多态)
![](https://img-blog.csdnimg.cn/fa7f66703c2a496c9af3a8b417629774.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YCG6L2u5Zue,size_20,color_FFFFFF,t_70,g_se,x_16)
Object类
Object
类是所有
Java
类的根基类。
如果在类的声明中未使用
extends
关键字指明其基类,则默认基类为
Object
类。
![](https://img-blog.csdnimg.cn/1f2fcc629e0a4d5cb7b977d4dbf4bda7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YCG6L2u5Zue,size_20,color_FFFFFF,t_70,g_se,x_16)
重写:
toString
方法:
默认返回:包名+
类名
+@+
哈希码(根据对象内存位置生成,唯一不重复)
根据对象内存位置 重复
可以重写!
super关键字
super是直接父类对象的引用。
可以通过super
来访问父类中被子类覆盖的方法或属性
![](https://img-blog.csdnimg.cn/84d7299f2e85443787c3bc8b2356d5cf.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YCG6L2u5Zue,size_20,color_FFFFFF,t_70,g_se,x_16)
父类方法的重写:
方法名、形参列表相同。
返回值类型和异常类型,子类小于等于父类。
访问权限,子类大于等于父类
构造方法调用顺序:
根据
super
的说明,构造方法第一句 总是:
super(…)
来调用父类对应的构造方法。
先向上追溯到
Object
,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
对象的比较—==和equals()
==:
比较两基本类型变量的值是否相等
比较两个引用类型的值即内存地址是否相等,即是否指向同一对象。
equals() :
两对象的内容是否一致
示例
object1.equals(object2) 如:p1.equals(p2)
比较所指对象的内容是否一样
是比较两个对象,而非两个基本数据类型的变量
object1 == object2 如:p1==p2
比较p1和p2
的值即内存地址是否相等,即是否是指向同一对象。
自定义类须重写equals()
,否则其对象比较结果总是
false
。
多态 polymorphism
多态性是OOP
中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终
只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和
扩展 性。
java中如何实现多态
?
使用多态的好处
?
引用变量的两种类型:
编译时类型(模糊一点,一般是一个父类)
由声明时的类型决定。
运行时类型(运行时,具体是哪个子类就是哪个子类)
由实际对应的对象类型决定。
多态的存在要有3
个必要条件:
要有继承,要有方法重写,父类引用指向子类对象
![](https://img-blog.csdnimg.cn/7a916295abc1450d8f5f916cc66e31e1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YCG6L2u5Zue,size_20,color_FFFFFF,t_70,g_se,x_16)
引用数据类型的类型转换
子类转换为父类:自动转换
上转型对象不能操作子类新增的成员变量和方法。
上转型对象可以操作子类继承或重写的成员变量和方法
如果子类重写了父类的某个方法,上转型对象调用该方法时,是调用的重写方法。
父类转换为子类:强制转换
(绝不是做手术,而是父类的真面目就是一个子类,否则会出现类型转换错误)
final关键字
final可以用来修饰变量,方法,类。
修饰变量:变量一旦被初始化便不可改变,相当定义了一常量。
final int x=3;
x=4;
修饰方法:final
方法是在子类中不能被覆盖的方法
final returnType methodName(paramList){...}
final void eat() { … }
修饰类:final
类是无法被任何类继承的。
final class finalClassName{ ... }
final class Person{ … }
抽象类
为什么需要抽象类?
如何定义抽象类
?
是一种模版模式。抽象类为所有子类提供了一个通用模版,子类可以在这个模版基础上进行
扩展。
通过抽象类,可以避免子类设计的随意性。通过抽象类,我们就可以做到严格限制子类的设
计, 使子类之间更加通用。
abstract class Animal {
abstract void shout(); //抽象方法没有方法体!
}
class Dog extends Animal{
@Override
void shout() {//必须重写父类的抽象方法否则编译通不过
System.out.println("旺旺旺!");
}
}
要点:
抽象方法和抽象类均必须用
abstract
来修饰。
抽象方法没有方法体,只需要声明不需实现。
有抽象方法的类只能定义能抽象类
相反抽象类里面的方法不一定全是抽象方法,也可能没有抽象方法。
抽象类可以包含属性、方法、构造方法。
抽象类不能实例化,及不能用
new
来实例化抽象类,只能用来被子类调用。
抽象类只能用来继承。
抽象方法必须被子类实现。抽象类的子类必须覆盖所有的抽象方法才能被实例化,否则还是
抽象类。
接口 interface
为什么需要接口
?
接口和抽象类的区别
?
接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实
现了:规范和具体实现的分离。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…
则必须能
…”
的思想。如果
你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏
人,则必须欺负好人。
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
项目的具体需求是多变的,我们必须以不变应万变才能从容开发,此处的“不变”就是“规 范”。
因此,我们开发项目往往都是面向接口编程!
接口相关规则
接口中所有方法都是抽象的。
即使没有显式的将接口中的成员用public
标示,也是
public
访问类型的。
接口中变量默认用 public static final
标示,所以接口中定义的变量就是全局静态常量。
可以定义一个新接口,用extends
去继承一个已有的接口。
可以定义一个类,用implements去实现一个接口中所有方法。
可以定义一个抽象类,用implements
去实现一个接口中部分方法。
如何定义接口
?
格式:
[访问修饰符
] interface
接口名
[extends
父接口
1
,父接口
2…] {
常量定义 //总是
public static final
方法定义 //总是:
public abstract
}
如何实现接口?
子类通过implements
来实现接口中的规范
接口不能创建实例,但是可用于声明引用变量类型。
一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public
的。
Java的类只支持单继承,接口支持多继承
C++
支持多重继承,
Java
支持单重继承
C++
多重继承的危险性在于一个类可能继承了同一个方法的不同实现,会导致系统崩溃。
Java
中,一个类只能继承一个类,但同时可以实现多个接口,既可以实现多重继承的效果和功能,
也避免的多重继承的危险性。
class Student extents Person implements Runner
,
Flyer {…}
注意:
extends
必须位于
implements
之前。
内部类
将一个类定义置入另一个类定义中就叫作“内部类”
类中定义的内部类特点
内部类作为外部类的成员,可以直接访问外部类的成员(包括private成员),反之则不行。
内部类做为外部类成员,可声明为private、默认、
protected
或
public
。
内部类成员只有在内部类的范围之内是有效的。
用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private
还要小的访问权限。
编译后生成两个类: OuterClass.class
和
OuterClass$InnerClass.class
内部类分类:
成员内部类 静态内部类 方法内部类 匿名内部类
匿名内部类
Anonymous
可以实现一个接口,或者继承一个父类。
只能实现一个接口。
适合创建那种只需要一次使用的类,不能重复使用。比较常见的是在图形界面编程GUI
里用得到。
匿名内部类要使用外部类的局部变量,必须使用final
修饰该局部变量。
![](https://img-blog.csdnimg.cn/a6f8088c9e48450ea53cd4f577707efa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6YCG6L2u5Zue,size_20,color_FFFFFF,t_70,g_se,x_16)
垃圾回收机制关键点
对象空间的分配:
使用new关键字创建对象即可。
对象空间的释放:
传统的C/C++语言,需要程序员负责回收已经分配内存。显式回收垃圾回收的缺点:
程序忘记及时回收,从而导致内存泄露,降低系统性能。
程序错误回收程序核心类库的内存,导致系统崩溃。
Java语言不需要程序员直接控制内存回收,是由JRE
在后台自动回收不再使用的内存,
称为
垃圾回收机制(Garbage Collection)。
可以提高编程效率。
保护程序的完整性。
其开销影响性能。Java虚拟机必须跟踪程序中有用的对象,确定哪些是无用的。
垃圾回收机制只回收JVM
堆内存里的对象空间。
对其他物理连接,比如数据库连接、输入流输出流、Socket
连接无能为力。
现在的JVM
有多种垃圾回收实现算法,表现各异。
垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。
可以将对象的引用变量设置为null
,暗示垃圾回收机制可以回收该对象。
程序员可以通过System.gc()
或者
Runtime.getRuntime().gc()
来通知系统进行垃圾回收,会有
一些效果,但是系统是否进行垃圾回收依然不确定。
垃圾回收机制回收任何对象之前,总会先调用它的finalize
方法(如果覆盖该方法,让一个新
的引用变量重新引用该对象,则会重新激活对象)。
永远不要主动调用某个对象的finalize
方法,应该交给垃圾回收机制调用。