2.4.面向对象高级
4.1 继承
4.1.1 定义
- 子类继承父类的特征(属性)和行为(方法)
4.1.2 子类实例化内存分析
- 创建子类对象时先创建父类对象
- super()关键字相当于获取父类地址
4.1.3 super
- 子类构造方法中super和this不能同时出现
- 调用super构造方法的代码,必须写在子类构造方法的第一行
4.2 重写(override)
- 参数列表、返回类型必须与被重写的方法相同
- 访问权限不能比父类中被重写的防范权限低
- 声明为static和private的方法不能被重写,但能够被再次声明
面试题:重写和重载区别
- 发生位置:
- 重写:父子类中
- 重载:一个类中
- 参数列表限制:
- 重写:必须相同
- 重载:必须不同
- 返回值类型
- 重写:必须相同
- 重载:与此无关
- 访问权限:
- 重写:子类不小于父类
- 重载:与此无关
- 异常处理
- 重写:异常范围可更小,但不能跑出新异常
- 重载:与异常无关
4.3 final
4.3.1 作用
- 修饰变量
- 修饰的局部变量,只能赋值一次,可先声明后赋值
- 修饰的成员变量,必须在声明时赋值
- 修饰类
- 不能被继承
- 修饰方法
- 不能被子类重写
面试题:fianL不能改变的是引用还是对象
- 不能改变的是引用
- 引用数据类型
- 基本数据类型
4.4 抽象类
4.4.1 原则
- 不能直接实例化
- 可以有自己的属性、非抽象方法
- 子类(非抽象类)需实现所有的抽象方法
- 只实现一部分父类抽象方法,则该子类为抽象类,若加abstract修饰后,可不实现父类抽象方法
- 若父类中有未实现的抽象方法,不管继承几代,子类(非抽象类),应实现剩余的抽象方法
- 父类引用指向子类对象时,若子类想调用所有父类的方法,应选择最邻近的父类引用
4.4.2 常见问题
- 抽象类能否使用final声明
- 不能,因为final修饰的类不能有子类,而抽象类必须有子类才有意义
- 抽象类能否有构造方法
- 能,且子类实例化时和普通类一致
4.4.3 抽象类和普通类的区别
- 抽象类必须由public或protected修饰,缺省默认public
- 抽象类不能使用new创建对象,但子类实例化时,父类也会被JVM实例化
- 子类(非抽象类)需实现父类所有方法
4.5 接口
4.5.1 要素
- 全局常量:默认缺省public static final,声明时赋初值
- 抽象方法(不能含有非抽象方法):默认缺省public abstract
4.5.2 优点
- 降低程序耦合性
- 利于程序扩展维护
4.5.3 接口和抽象类区别
- 接口被实现,抽象类被继承
- 接口中的变量时全局常量,抽象类中的变量是普通变量
- 接口中的方法都是抽象方法,抽象类中的方法可以有非抽象方法
- 接口无构造方法,抽象类有构造方法
- 接口无static修饰的方法,抽象类**有*
- 接口可被多继承,抽象类只能被单继承
4.6 多态
4.6.1 体现
- 对象多态:子类是父类的一种形态
- 方法多态:
- 重写:子父类方法
- 重载:一个类中方法体现
4.6.2 instanceof
4.6.2.1 作用
- 判断某一对象是否是该类的实例
4.6.2.2 用法
- 实例对象 instanceof 类
Student s=n(Student)new Person();
if(s instanceof Student) ...
4.6.3 对象类型转换
- 转型:看声明类型权限,权限高则为向上,反之向下
- 向上转型:父类实例-->子类实例(安全,父类引用指向子类对象)
- 向下转型:子类实例-->父类实例(不安全,需通过instanceof判断)
4.7 内部类 (不常用)
4.7.1 类型
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
4.7.2 用法
4.7.2.1 成员内部类
- 创建内部类对象需依托外部对象
- 内部类对象创建结束后,可无条件访问外部类属性和方法
- 访问方式:外部类.this.外部类属性/方法
- 内部类和外部类具有相同属性或方法时,默认访问内部类的成员
public class Outer {
int x=10;
public static void main(String[] args) {
Outer.Inner i=new Outer().new Inner();
i.say();
}
class Inner{
private int x=20;
void say() {
System.out.println("内部类方法1");
System.out.println(x);//成员变量x的值
System.out.println(Outer.this.x);//调用外部类属性
Outer.this.say();//调用外部类方法
}
}
void say() {
System.out.println("外部类方法");
}
}


4.7.2.2 静态内部类
- 创建内部类对象无需依托外部类对象
- 不能使用外部类非static成员变量和方法
- 使用方法:外部类.属性/方法
public class Outer2 {
static int x=10;
public static void main(String[] args) {
Outer2.Inner2 i = new Outer2.Inner2();
i.say2();
}
static class Inner2{
void say2() {
System.out.println("内部类方法2");
System.out.println(Outer2.x);//调用外部类属性
Outer2.say2();//调用外部类静态方法
}
}
static void say2() {
System.out.println("外部类方法2");
}
}


4.7.2.3 局部内部类
- 必须继承一个类或实现一个接口
- 继承的类可以是抽象类或普通类
//person接口
public interface Person {
void say();
}
public class Outer3 {
public static void say(Person p) {
p.say();
}
public static void main(String[] args) {
class Student implements Person{
@Override
public void say() {
System.out.println("内部类方法3");
}
}
Student s=new Student();
Person p=new Student();
say(s);
say(p);
}
}


public class Animal {
void say() {
System.out.println("内部类方法4");
}
}
public class Outer4 {
public static void say(Animal a) {
a.say();
}
public static void main(String[] args) {
class Dog extends Animal {
@Override
void say() {
super.say();
}
}
Dog d=new Dog();
say(d);
}
}

4.7.2.4 匿名内部类
4.7.2.4.1 定义
- 局部内部类的一种,创建形式不同
- 内部类后加分号
4.7.2.4.2 要点
- 必须继承或实现一个接口
- 不能定义构造函数
- 不能存在任何的静态成员变量和静态方法
- 不能是抽象类,必须实现继承的类或实现的接口的所有抽象方法
- 只能访问final型局部变量
public class Outer5 {
public static void say(Person p) {
p.say();
}
public static void main(String[] args) {
Person p=new Person() {
@Override
public void say() {
System.out.println("内部类方法5");
}
};
say(p);
}
}

public class Outer6 {
public static void say(Animal2 a2) {
a2.say();
}
public static void main(String[] args) {
Animal2 a2=new Animal2() {
@Override
void say() {
System.out.println("内部类方法6");
}
};
say(a2);
}
}

面试题:内部类为何只能访问final局部变量
- java1.8前局部变量需final定义,1.8后可缺省
- 内部类会被单独编译成一个字节码文件,其中用到的局部变量值是通过备份所得,为了保证值一致性,系统规则限制值不可更改
4.8 包装类
4.8.1 方法
4.8.2 装箱
Integer a=new Integer(10);//手动,已过时
Integer b=Integer.valueOf(20);
Integer a=20;//自动
4.8.3 拆箱
int b=a.intValue();//手动
int b=a;//自动
4.8.4 和字符串转换
int a=Integer.parseInt(text);//text需为数字
4.9 可变参数(不常用)
4.9.1 位置
- 只能出现在参数列表的最后
4.9.1 用法:参数类型+省略号+形参名
int sing(int... nums) {
int n=0;
for (int i = 0; i < nums.length; i++) {
n += nums[i];
}
return n;
}
4.10 异常
4.10.1 定义
- 异常是在程序中导致程序中断运行的一种指令流。
4.10.2 体系结构
- Throwable存在两个子类:
- Error:JVM发出的错误操作,只能尽量避免,无法用代码处理。
- Exception:所有程序中的错误,所以一般在程序中将进行try…catch的处理。
4.10.2.1 类型(面试题)
- 受检异常(编译时异常)
- 非受检异常(运行时异常)
4.10.3 处理格式
try{// 有可能发生异常的代码段
}catch(异常类型1 对象名1){ // 异常的处理操作
}catch(异常类型2 对象名2){// 异常的处理操作
}finally{ // 异常的统一出口 }
4.10.4 处理流程
- 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
- 若异常发生在try语句,则会自动找到匹配的catch语句执行
4.10.5 finally
4.10.5.1 定义
- 不管是否产生了异常,最终都要执行此段代码。
面试题:什么情况下finally语句不执行
- 代码情况:System.exit(0);//退出JVM
- 其他情况:断电,程序退出内存
扩展:即便try语句中有return,finally语句也会执行
4.10.5.2 对return值的影响
- 引用数据类型值受影响
class Person {
int age;
}
public static void main(String[] args) {
System.out.println("返回后的age值:" + fun2().age);//20
}
public static Person fun2() {
Person p = new Person();
try {
p.age = 10;
return p;
} catch (Exception e) {
return null;
} finally {
p.age = 20;
System.out.println("修改后的age值:" + p.age);//20
}
}


- 基本数据类型值不受影响
public static void main(String[] args) {
System.out.println("返回的a值为:"+fun1());//10
}
public static int fun1() {
int a=10;
try {
return a;
} catch (Exception e) {
return 0;
}finally {
a=20;
System.out.println("修改后的a值为:"+a);//20
}
}


- 原因
- retrun在返回值之前有个准备过程,finally在此期间执行
- return返回的值是通过备份所得
- 对于引用数据类型,备份的是堆空间中的地址,对于基本数据类型,备份的是初始值
- 要点
- 修改后的值和返回后的值不一定相同
4.10.6 throws
- 传参导致异常,应将异常抛出(方法抛)
4.10.7 throw
- 人为抛出一个异常(代码内部抛)
welcome~the interesting soul







浙公网安备 33010602011771号