继承
继承——尽量少使用继承,应该采用接口进行替换
当不知道采用继承还是接口的时候,应该优先考虑采用接口。
继承用来表示类和类之间的关系
public class Father {
// 很多方法和属性
}
public class Child extendsFather {
//
}
继承可以继承哪些内容?
可以被继承的内容只有属性和方法。构造块和构造器是无法继承的。
虽然构造块和构造器是无法继承的,但是会在创建子类对象的时候被自动调用。
当父子类中包含静态或非静态的构造块以及构造器的时候
1.static内容一定是先执行完毕的(也是先父后子)
2.父类的非静态内容一定优先于子类执行完毕
父类
public class Father {
public Father() {
System.out.println("父类的构造器");
}
{
System.out.println("父类的构造块");
}
static {
System.out.println("父类中的静态块");
}
}
子类
public class Child extends Father {
public Child () {
System.out.println("子类的构造器");
}
{
System.out.println("子类的构造块");
}
static {
System.out.println("子类中的静态块");
}
public static void main(Sring[] args) {
// 不创建对象时,父类和子类的构造块和构造器都不会执行
Child child = new Child();
}
}
super关键字(注意对比this)
1. 调用父类的属性和方法super.属性 super.方法()
2. 调用父类构造器——所有类的构造器中都有一个隐含的super();
super() 调用父类构造器必须出现在构造器的第一行,这个要求和this()一样
那就意味着 super() 和 this() 不能同时出现
考点:注意看父类是否有不带参数的构造器
public class Child extends Father {
public Child() {
System.out.println("子类的构造器");
}
public Child(int i) {
super();
// this(); 不能同时书写this()和super()
System.out.println("子类的带参数构造器");
}
void g(){
super.f();
this.f();
}
public static void main(String[] args) {
}
覆盖(重写)
重写和重载的思路类似。因为一个类中不允许有相同的方法名存在,但是重载和重写是两个例外。
1.方法签名必须完全一样(方法签名 = 方法名 + 参数列表)
2.返回类型必须相同或者更窄(子类)
3. 修饰符必须相同或更宽 (更窄private < defalut < protected < public 更宽)
public class Father {
protected Father f() {
return null;
}
}
public class Child extends Father {
@Override // 这个注解的作用只是为了帮助校验一下这个方法f是不是一个正确的重写
public Child f() {
return null;
}
}
重写必须有父类和子类
重载可以只是单一的类,也可以出现在父子类中
// 第一种
protected Father f() {
return null;
}
// 第二种
void f(double d) {
}
// 第三种
public class Child extends Father{
public Child f(int i){ //重载
return null;
}
}
以上父子类中的三个方法f是互相重载的。
抽象类:对于现实世界中的抽象概念,可以使用抽象类来表示。比如形状。
抽象类的用处实际上就是用来作为父类使用。
public abstract class A {
}
抽象类不能创建对象
抽象类可以有构造器
public abstract class A {
public A() {
}
public static void main(String[] args) {
A a = new A(); //错误,抽象类不能创建对象
}
}
既然抽象类不能创建对象,那么要构造器有什么用处?
抽象类虽然不能创建对象,但是可以被继承。当它有了子类后,子类的构造器一定会调用父类的构造器。 所以抽象类的构造器是用于子类创建对象是被优先调用的。
public abstract class A {
public A() {
System.out.println("抽象类A的构造器");
}
}
public class B extends A{
public B() {
System.out.println("子类B的构造器");
}
public static void main(String[] args) {
B b = new B();
}
}
抽象方法
用abstract修饰的方法就是抽象方法。抽象方法不能有方法体。
如果一个类中包含抽象方法,那么这个类就必须被标记为抽象的。
但是要注意,一个抽象类中可以没有抽象方法。
抽象方法怎么用?
抽象方法就是用来被实现的,谁继承了包含抽象方法的类,就必须实现抽象方法或者将自己变为抽象类。
public class A {
public void f() {
}
}
public abstract class B extends A{
@Override
public abstract void f();
//可以把父类中的方法在子类中覆盖为抽象方法
}
内部类: 面试经常问有哪些内部类,它们的特点是什么。
1.嵌套内部类
public class Outer { //类可以是defalut和public的
class inner { //内部类可以是private,defalut,protected,public的任意一种
}
}
2.静态内部类
public class Outer {
static class inner {
}
}
3.局部内部类: 出现在方法中的类
public class Outer {
public void f() {
class C{
}
}
}
4.匿名内部类
通常是new 类名/接口名{
}
new后面的类名/接口名中一定包含抽象方法,在匿名内部类中给出抽象方法的实现即可。
abstract class A {
abstract void f();
abstract void g();
}
public class Outer {
public static void main(String[] args) {
A a = new A() {
@Override
void f() {
System.out.println("f");
}
@Override
void g() {
System.out.println("g");
}
};
a.f();
a.g();
}
}
异常
- 异常的捕获: try-catch
- 异常的声明:throws:声明异常和是否发生这种异常是两回事。
- 异常的抛出:throw
所有的异常都是对象,抛出异常实际上就是产生一个对象。
catch捕获异常,实际上可以理解为一个异常对象被当做参数传递到catch中。
try {
throw new IOException(); // 异常的抛出
} catch (IOException e) { // 异常的捕获
e.printStackTrace();
}
try {
throw new IOException();
} catch (ArrayIndexOutOfBoundsException | ArithmeticException | IOException e) {
//当try中可能出现多个异常,且这些异常的处理方式都是相同的情况下,可以写为上面的形式。
e.printStackTrace();
} catch (Exception e) {
System.out.println("xxxx");
}
try (InputStream is = new FileInputStream("a")) {
// try后面放圆括号是为了自动关闭其中的内容,而且这个关闭一定是通过调用close方法来完成
// 哪些内容可以自动关闭? 实现了Closeable接口的内容是可以用于这种语法中的
System.out.println(is.available());
} catch (IOException e) {
e.printStackTrace();
}
I/O输入/输出
Files是一个工具类,用于处理文件、文件夹(目录)
这个工具类不涉及文件中的内容,只是负责建立、删除、判断是否存在等操作。
Linux不严格区分文件还是文件夹,一切都是文件夹
// Path表示路径,即文件或者文件夹的路径和名字
// 一个路径是否存在、不区分到底它是文件还是文件夹,这要取决于后续调用的方法
Path file = Path.of("D:\\aa.txt");
Path dir = Path.of("D:\\abc");
if (Files.notExists(file))
Files.createDirectory(file); // 建文件夹
if (Files.notExists(dir))
Files.createDirectory(dir); // 建立文件夹
System.out.println("是否隐藏?" + Files.isHidden(file)); // 判断一个文件或者文件夹是否是隐藏的
System.out.println("是否可执行?" + Files.isExecutable(file)); // exe才是可执行
System.out.println("是否可被修改?" + Files.isWritable(file)); // 是否可被修改
Files.deleteIfExists(file); // 如果文件或文件夹存在则将其删除
Files.deleteIfExists(dir);
}