2020-07-20(接口、各种类、异常)
个人笔记,没有参考价值😈,为节约您的学习时间,请绕道查找其他资料
接口中的方法都是且只能用 public abstract 修饰,所以这两修饰符也可以省略
接口中不能定义局部变量,定义的变量默认都是 public static final 修饰的,这三个修饰符同样可以省略
接口中可以有缺省实现的方法,要用 default 修饰(Java8),接口中有 default 修饰的方法在继承类中可以选择实现,也可以选择不实现,直接用 default 那个实现也是可以的。如果一个类实现了两个接口,并且两个接口里有相同的接口实现,编译器会报错
也可以有私有的方法,用 private 修饰(Java9)
可用的类中必须要实现接口中的所有方法
抽象类不用(如图示)
接口类、抽象类、可实例化的类
静态内部类是在类中用 static 修饰的类,可以有访问控制符。静态内部类和静态方法,静态变量一样,都是类的组成部分。静态内部类也是类,在继承,实现接口方面是一样的
package com.geekbang.supermarket;
public class Phone extends MerchandiseV2 {
// 给Phone增加新的属性和方法
private double screenSize;
private CPU cpu;
private int memoryG;
private int storageG;
private String brand;
private String os;
// >> TODO 静态内部类,是在类中使用static修饰的类
// >> TODO 静态内部类,可以有访问控制符。静态内部类和静态方法,静态变量一样,都是类的静态组成部分
// >> TODO 静态内部类也是类,在继承,实现接口方面,都是一样的。以后我们讲的类,不特殊说明,在这方面都是一样的
public static class CPU {
private double speed;
private String producer;
public CPU(double speed, String producer) {
this.speed = speed;
this.producer = producer;
}
public double getSpeed() {
// >> TODO 静态内部类,代码和这个类本身的访问权限一样,可以访问外部(Phone)的private属性
// >> TODO 注意,这并不少说它可以访问private变量,
// >> TODO 静态内部类是静态的,就好像静态方法一样,没有this自引用,可以通过引用访问Phone对象的private属性
// 仅作演示访问性,不具有实际意义
Phone phone = null;
phone.memoryG = 99;
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public String getProducer() {
return producer;
}
public void setProducer(String producer) {
this.producer = producer;
}
@Override
public String toString() {
return "CPU{" +
"speed=" + speed +
", producer='" + producer + '\'' +
'}';
}
// >> TODO 静态内部类,里面可以有任意合法的类的组成部分,包括静态内部类
// public static class ABC{
//
// }
}
public void accessStaticClass(){
// >> TODO 同样,外部类也可以访问静态内部类(CPU)的private属性
// 仅作演示访问性,不具有实际意义
this.cpu.producer = "";
}
public Phone(
String name, String id, int count, double soldPrice, double purchasePrice,
double screenSize, double cpuHZ, int memoryG, int storageG, String brand, String os
) {
this.screenSize = screenSize;
// >> TODO 可以像平常的类一样使用静态内部类
this.cpu = new CPU(cpuHZ, "Default");
this.memoryG = memoryG;
this.storageG = storageG;
this.brand = brand;
this.os = os;
this.setName(name);
this.setId(id);
this.setCount(count);
this.setSoldPrice(soldPrice);
this.setPurchasePrice(purchasePrice);
}
public void describePhone() {
System.out.println("此手机商品属性如下");
describe();
System.out.println("手机厂商为" + brand + ";系统为" + os + ";硬件配置如下:\n" +
"屏幕:" + screenSize + "寸\n" +
"cpu信息:" + cpu + " \n" +
"内存" + memoryG + "Gb\n" +
"存储空间" + storageG + "Gb\n");
}
}
// >> TODO 非共有类和静态内部类,实际区别就在于能否访问类的private成员
class Memory {
private long capacity;
private String producer;
public Memory(long capacity, String producer) {
this.capacity = capacity;
this.producer = producer;
}
public void test(){
// >> TODO 在类的外面的代码,不能访问类的private成员
// 仅作演示访问性,不具有实际意义
// Phone ph = null;
// ph.screenSize = 9;
}
public long getCapacity() {
return capacity;
}
public void setCapacity(long capacity) {
this.capacity = capacity;
}
public String getProducer() {
return producer;
}
public void setProducer(String producer) {
this.producer = producer;
}
}
成员内部类是在类中直接定义一个类,可以有访问修饰符。成员内部类和成员方法、成员变量一样,都是类的组成部分。
成员内部类不可以包含任何静态的成分,比如静态方法,静态变量,静态内部类,否则会造成内外部类初始化问题,可以有final static的基本数据类型变量
成员内部类中有一个外部类的引用,其访问外部类的对象的成员属性就是使用这个引用,完整写法是:类名.this.属性/方法
匿名类 is coming!
关于各种类的小总结
- 枚举
枚举就是有固定个数实例的类;枚举的父类是Enum - 非公有类
最不特殊的类,可以认为就是被缺省访问控制符修饰的类,也就是说,和public class 的区别仅仅是可以被访问的范围不一样;如果一个文件只有非公有类,那么类名可以和文件名不一样 -
内部类
内部类的特殊之处在于可见性和可以访问的数据以及方法,内部类会被认为是类本身的代码,所以外部类的 private 成员对其可见;
三种内部类的对比记忆:
三种内部类 - 匿名类
匿名类是一种创建接口和抽象类对象的语法,任何可以 new 一个对象的地方都可以使用匿名类;匿名类只能实现/继承一个接口/抽象类,本身没有名字;如果是在成员方法或者成员方法赋值时创建匿名类,那么会有外部对象的 this 自引用;匿名类也可以访问外部类的 private 属性
理解: 类只有一个,但实例是可以多个~
异常
所有异常的父类:Throwable
- 按异常的继承关系分类
两类异常:Error 和 Exception
其中 Error 是程序不可修复的(比如磁盘不够用等等资源不够用之类的...)
和业务逻辑有关的,可以补救的就是 Exception -
按处理方式不同分类
checked excepted : 语法要求必须要用try catch 或者 throws 语句处理的异常
unchecked exception : 语法不要求要用 try catch 或者throws 语句处理的异常
Error 和 RuntimeException 是 unchecked exception 的父类,我们一般使用 RuntimeException
RuntimeException的子类们...,👆这些都是unchecked exception
如果继承链路中不是继承的error 也不是继承的 RuntimeException ,那么这种就是checked exception
如果一个接口的方法定义中没有抛出异常,那么在他的实现类中该方法也不建议抛出异常,因为这样会改变接口中这个方法的定义。但是可以在实现类中try catch 住异常
show code
IntfWithEx.java (接口定义)
public interface IntfWithEx {
void danger() throws Exception;
void safe();
}
ImplIntfWithEx.java (实现类)
public class ImplIntfWithEx implements IntfWithEx {
@Override
public void danger() throws Exception {
// >> TODO 接口中声明了抛出异常,实现类中可以抛,也可以不抛。抛的话必须是接口声明的类或其子类
throw new Exception("");
}
@Override
public void safe() {
// >> TODO 接口中没有声明抛出异常,实现类中可以抛RuntimeException,也可以不抛。
// >> TODO 如果抛 checked exception,就会出错
// >> TODO 可以选择catch住 checked exception,然后将它封在RuntimeException里
// throw new Exception();
// throw new RuntimeException();
}
}
当 ImplIntfWithEx 类中safe() 方法需要抛出异常时应该try catch 住
public class ImplIntfWithEx implements IntfWithEx {
@Override
public void danger() throws Exception {
// >> TODO 接口中声明了抛出异常,实现类中可以抛,也可以不抛。抛的话必须是接口声明的类或其子类
throw new Exception("");
}
@Override
public void safe() {
// >> TODO 接口中没有声明抛出异常,实现类中可以抛RuntimeException,也可以不抛。
// >> TODO 如果抛 checked exception,就会出错
// >> TODO 可以选择catch住 checked exception,然后将它封在RuntimeException里
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
// throw new RuntimeException();
}
}
Java 异常的最终归宿,要么沿着方法调用栈一路抛,最终造成当前线程出错退出,要么被 catch 住。
try catch finally 在finally 中给return用的变量赋值是没有用的