面向对象的三大特征
- 继承
关键字:extends 扩展
语法: public class A extends B
理解: 类A对类B进行扩展
在现实世界中的体现就是特殊与一般的关系。
ISA原则: A is a B A是一种B
本质上:A是一种特殊的B A是特殊 B是一般
燕子(A)是一种鸟(B)
动物(A)是一种鸟(B) 逻辑不成立
Class A 称之为 “子类” 特殊类
Class B 称之为 “父类”“超类” 一般类
Java是单继承的。一个类只能有唯一的直接父类
Java中如果某个类没有写明父类,系统让它默认继承java.lang.Object类
当父类没有无参构造方法(包括显式声明和系统默认提供)时,子类必须显式地在自己的构造方法的第一句调用父类的某个构造方法。
如果父类有无参构造方法,子类可以不写明调用,系统会默认调用父类的无参构造方法
super关键字:表示当前对象的父类对象引用
super.xxx 表示访问了父类的某个属性
对于继承自父类的属性super.xxx this.xxx xxx本质是一样的
对于子类自有的属性this.xxx xxx
super.xxx(); 表示访问了父类的某个方法 相当于 xxx();
super(); 访问了父类的某个构造方法
引用数据类型的内存分配
引用数据类型的类型转换
(1)上溯造型 子类对象转父类对象(重点)
规则:
子类对象向父类对象可以自动转换
Parent p; //声明了父类的变量(对象)
P = new Child(); //使用子类构造方法去实例化
上溯体现的现实含义:将一个特殊的类重新看做一般的类。会失去特殊类中的独有的属性和方法
如果是Parent p = new Child(); p对象本质上是Child,此处将它当作Parent看待,丢失Child自有的特殊属性和特殊行为(方法)
(2)下溯造型 父类对象转子类对象
父类对象需要强制转换至子类对象,转换成功的前提:该父类对象必须是由该子类new出来或由该子类对象上溯造型转换过去的
(3)如果类型之间不存在继承关系,则一定不能互相转换
下溯造型成功
下溯造型失败:句柄无法找到子类的类型
- 封装
封装:
包级别:关联性较大的一些类,放入到同一个包中。 内聚
有同类性质的一些类,放入到同一个包中。
类级别:向逻辑相关的共性放入到一个类中
四种访问权限
访问权限 | 类的内部 | 同一个包下的其他类 | 不同包下的子类 | 不同包下的其他类 |
private(私有) | OK | NG | NG | NG |
什么都不写(默认) | OK | OK | NG | NG |
protected(保护) | OK | OK | OK | NG |
public(公有) | OK | OK | OK | OK |
Java类的声明只能使用public 或 默认 这两个级别
其余属性,方法,构造方法等可以使用权限的地方,四种都可以使用。
面试:在子类中访问父类的某个属性,这个属性应该(至少)设为什么访问权限? protected
做成JavaBean
一个类中,只有私有属性和这些属性对应的setter与getter方法,这样的类通常被称为JavaBean
通过设置setter和getter可以控制某个属性为只读或者只写。比起public的方式更加灵活。
- 多态
父类(一般)与子类(特殊)在同一行为上,有不同的表现形式。
通过方法重写(方法的覆盖 override)体现多态
重写的规则:
子类改写父类同名同参同返回值类型的方法,这种行为就是重写(方法的覆盖),子类方法的访问权限必须大于等于父类的方法。
父类的私有方法不参与重写
调用时优先调用子类对象的方法
笔试:重载与重写的区别
重载:在同一个类,方法同名不同参数,与返回值类型无关
重写:在继承关系的类中,子类改写父类同名同参同返回值类型的方法。
笔试:
Public class Parent{
public void haha();
}
Public class Child extends Parent{
}
以下方法那些可以定义在Child类中
public int haha() NG 既不是重载也不是重写
public void haha() OK 重写
public int haha(int a) OK 重载
…
多态的形成条件
- 发生在继承或者实现的关系中
- 子类要重写父类的方法
- 父类的声明,子类去实例化 (上溯造型)
达成效果:
调用父类对象的方法,因为是子类实例化的,所以执行的是子类的方法。
多态的应用例子
抽象类
接口
static 静态关键字
final 关键字
设计模式—单例模式
单例是每次实例化的对象都是这一个
- 抽象类
抽象关键字:abstract 可以修饰类和方法
抽象类中可以有抽象方法,也可以有普通方法
抽象类的本质:定义一个类其中可能某些细节没有实现,这个类就是作为父类出现的
抽象方法的本质:方法的细节没有实现,就是为了给出定义,具体的细节有子类重写实现
子类继承了抽象类,必须实现父类中所有的抽象方法的细节,除非子类也是个抽象类。
抽象类不允许进行实例化 。可以使用临时的匿名类完成临时的细节化。
练习:创建Plane(飞机)类,fly方法 -- 根据不同的飞机有不同的飞行方式
PenQiPlane 喷气式飞机 文字输出利用引擎的反推力
LXJPlane 螺旋桨式飞机 文字输出利用牵引力
HeliPlane 直升机 文字输出 利用悬转力
- 接口
接口不是类,不能实例化。
接口是一些行为的定义或载体。
接口中只能定义常量(final)或抽象(abstract)方法
Final和abstract在接口中可以省略不写
接口一般表述的是行为,命名规范:动词+able
Java中单继承(extends)多实现(implements)
一个Java类可以实现多个接口
类与类之间的关系
继承(extends)关系,只能有一个直接父类
Public class A extends B
类与接口之间的关系
实现(implements)关系,可以实现多个接口
一个类可以继承父类之后同时又实现多个接口
Public class A implements B,C
Public Class A extends B implements C,D
接口与接口之间的关系
继承(extends)关系,可以继承多个接口
public interface A extends B,C
笔试/面试:抽象类与接口的区别?
抽象类是class,接口是interface
抽象类中可以有属性,抽象方法,非抽象方法
接口中只能有常量属性和抽象方法
抽象类是作为父类被子类继承,类的继承是单继承
接口是作为接口被子类实现,类的实现是多实现
作业:
创建一个Unit类,表示所有可以参与到游戏中的单位
属性
名字
最大生命值
当前生命值
行为
Show -- 没有细节
攻击是一种行为….
创建一个NPC类,是一种Unit,可以进行攻击
属性
最小攻击力
最大攻击力
行为
攻击
Show 显示当前生命值
创建Player类,是一种Unit,可以攻击
最小攻击力
最大攻击力
暴击几率
暴击倍数
行为
攻击
Show,显示当前生命值,暴击几率
测试类Test
创建一个NPC对象和一个Player对象进行互相攻击
Static静态关键字
被static修饰的内容,不再属于对象,而是属于类。(与对象无关)
无需创建对象,即可使用,通过类名.xxx进行调用。
Public class Haha{
Public void display() …
Public static void show()…
}
Haha h = new Haha();
h.display(); //普通方法需要创建对象后,通过对象调用
Haha.show(); //静态方法无需创建对象,直接通过类名.xxx调用
可以修饰三种内容
- 修饰属性
所有的对象共享唯一一个静态属性,可以通过类名.xxx调用
某个对象将静态属性的值更改,其他属性看到的属性值全都变化
- 修饰方法
所有的对象共享静态方法,可以通过类名.xxx()调用
静态方法主要是用于制作工具性质的方法。
- 修饰代码块
代码块中的代码在类加载时,执行一次,且最多只被执行一次
类加载的时机
- 当第一次使用了这个类(第一次调用了静态属性或静态方法或第一次new了它的对象)
- 使用了反射机制Class.forName加载了这个类
静态代码块中的代码主要也是为了初始化。
静态方法和静态块中访问属性的原则:
静态方法,静态块可以直接访问类的静态属性和其他方法,不能直接访问非静态的属性和方法(静态只能访问静态,非静态可以访问静态)
原因:在类加载时,静态内容已经载入内存,但无法确定非静态的内容是否已经加载成功,所以静态方法或静态块中不能调用非静态的内容
Final 最终关键字
可以修饰
类:被final修饰的类,不允许有子类
属性/变量:被final修饰的属性或变量,不能改值,叫做“常量”
在类中声明 public static final int xxx = xxx 表示常量
比如:Math.PI
方法:被final修饰的方法不能被子类重写
笔试面试:
- final关键字的作用?
将修饰类,属性,方法的特征描述
- final与abstract能不能同时使用?
不能。Abstract让子类继承同时实现abtract方法
Final阻止继承阻止重写。两者意义相反不能同时使用
- public static final int[] a = new int[5];
a[0] = 5;
public static final int b = 3;
b = 5;
数组的内存地址不能改,数组里的内容是可以改的。
设计模式—单例模式(非常重要)
单例:单个实例(对象),在整个程序运行的生命周期,这个类最多只能有一个实例对象。这种类就是单例类
饿汉式单例:不管实例是否使用,先创建实例
在Java中个人推荐饿汉式单例 没有synchronized关键字,效率较高
public class HungrySingleton {
private static final HungrySingleton h = new HungrySingleton();
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return h;
}
}
懒汉式单例:不着急创建实例,什么时候第一次使用,什么时候创建
public class LazySingleton {
private static LazySingleton l;
private LazySingleton() {}
public synchronized static LazySingleton getInstance() {
if(l == null) {
l = new LazySingleton();
}
return l;
}
}
Java中的异常及异常处理
Java对于异常的处理是管理,异常也是一种类型。
java.lang.Throwable类 所有问题的父类
问题包含错误(Error)和异常(Exception)
错误(Error):一般来说是程序无法修复的。通常是由于“物理”原因造成的问题。比如:网线断了,硬盘坏了,光盘碎了…
异常(Exception):一般来说是程序可控的问题。通常是由于“逻辑”原因造成的问题。比如:访问了不该访问的内存(下标越界),除数为0,空指针异常,下溯造型时发生的异常…
Exception主要分为两个阵营
- 运行时异常(非检查性异常) RuntimeException及其子类
编译时不会强制检查处理,但程序逻辑不正确时,在执行时程序就会发生异常
Java.lang.ArithmeticException: 整数除数为0
Java.lang.ClassCastException: 下溯造型类型转换异常 ***
Java.lang.ArrayIndexOutOfBoundsException:数组下标越界 **
java.lang.NullPointerException:空指针异常 ****
笔试题:
(1)列出你所接触过的运行时异常
(2)如何处理运行时异常
不应该发生的异常,出现问题检查代码,杜绝错误的逻辑
空指针异常:在调用可能为null对象前,先进行判断。
- 检查性异常(会在编译时出错)
强制开发者在程序中处理异常,如果不处理程序编译不通过
java.lang.InterruptedException:线程中断异常
处理异常的方式
- throw / throws 上报异常
将异常继续上报给调用者,有调用者继续决定
一个方法可以throws多个异常
Public void haha() throws XXXException, YYYException{…}
- try…catch…finally… 处理异常
自己解决异常
Try{
}catch(XXXException e){
} catch(YYYException e){
}…
catch(ZZZException e){
}
当try中的代码发生了XXXException会进入第一个catch执行
当发生了YYYException会进入第二个catch执行…
捕获范围越大的Exception的catch分支应该放在越下面。
Finally关键字:无论如何try…catch…finally都会执行finally中的代码 try中或catch中有return,finall中的代码也会在return之前完成执行
Trt不能单独使用,catch不能单独使用,finally也不能单独使用
Try可以与catch联合使用,也可以与finally联合使用
也可以与catch和finally同时使用
Catch不能和finally联合使用
通常的用法:
- try…catch…
- try…catch…finally
自定义异常:
编写类继承某个Exception类即可
练习:
创建一个Student类
属性
姓名 String
年龄 int
Student人数 int 静态,初始值为0
每调用一次构造方法 人数++
构造方法为姓名和年龄赋值
年龄必须在[18,24]之间,否则抛出一个自定义的异常
方法
Display方法:显示姓名,年龄和人数
测试类Test的main方法中
创建任意5个Student的对象,并调用它们的display方法完成显示