一,继承
1,继承
继承可以基于已有的类创建新的类。继承已存在的类就是复用(继承)这些类的方法,而且可以增加一些新的方法和字段,使新类能够适应新的情况。
Tip:子类在覆盖一个超类的方法时,子类方法不能低于超类方法的可见性。
2,访问权限
4个访问修饰符:
1,仅对本类可见——private。
2,对外部完全可见——public。
3,对本包和所有子类可见——protected。
4,对本包可见——默认,不需要修饰符。
3,抽象类
抽象类和抽象方法都使用 abstract 关键字进行声明。如果一个类中包含抽象方法,那么这个类必须声明为抽象类。
抽象类和普通类最大的区别是,抽象类不能被实例化,只能被继承。
4,多态
一个对象变量可以指示多种实际类型的现象称为多态。在运行时能够自动的选择适当的方法,称为动态绑定。
5,重载和重写的区别
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法。
重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。
重写:重写就是子类对父类方法的重新改造,外部样子不能改变,内部逻辑可以改变。
二,反射
反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。
能够分析类能力的程序称为反射。反射机制可以用来:
(1)在运行时分析类的能力。
(2)在运行时检查对象,例如,编写一个适用于所有类的toString方法。
(3)实现泛型数组操作代码。
(4)利用method对象,这个对象很像C++中的函数指针。
Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect 类库主要包含了以下三个类:
Field :可以使用 get() 和 set() 方法读取和修改 Field 对象关联的字段;
Method :可以使用 invoke() 方法调用与 Method 对象关联的方法;
Constructor :可以用 Constructor 的 newInstance() 创建新的对象。
三,接口
为了让类实现一个接口,通常需要完成下面两个步骤:
1,将类声明为实现给定的接口。
2,对接口中的所有方法提供定义。
Tip:
1,接口中的所有方法都自动是public方法。因此,在接口中声明方法时,不必提供关键字public。
2,接口中绝不会有实例字段,接口中的字段都是默认static,final的。在java8之前,接口中绝对不会实现方法,从 Java 8 开始,接口也可以拥有默认的方法实现。
1,lambda表达式
lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。lambda表达式不仅能够简化代码还能够提升运行的效率。最好可以把lambda表达式看成一个函数,而不是一个对象,另外要接受可以lambda表达式可以传递到函数式接口。
函数式接口
Arrays.sort(planets , (first , second) -> first.length() - second.length());
var timer = new Timer(1000 , event ->
System.out.print(""));
方法引用
lambda表达式中还可以涉及一个方法:
var timer = new Timer(1000 , event -> System.out.println(event));
可以直接把println方法传递到Timer构造器:
vartimer= newTimer(1000 , System.out::println);
方法引用指示编译器生成一个函数式接口的实例,覆盖这个接口的抽象方法来调用给定的方法。
方法引用中要用::运算符分隔方法名与对象或类名。主要有三种情况:
1,object::instanceMethod
2,Class::instanceMethod
3,Class::staticMethod
在第一种情况下,方法引用等价于向方法传递参数的lambda表达式。对于System.out.println,对象是System.out,所以方法表达式等价于x->System.out.println(x)。
对于第二种情况,第一个参数会称为方法的隐式参数。例如:String::compareToIgnoreCase等同于(x,y)->x.compareToIgnoreCase(y)。
在第三种情况下,所有参数都传递到静态方法:Math::pow等价于(x,y)->Math.pow(x,y)。
四,内部类
内部类是定义在另一个类中的类。使用内部类的原因:
1,内部类可以对同一个包中的其他类隐藏。
2,内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据。
1,局部内部类
在一个类的一个方法中局部地定义这个类就称之为局部内部类。
声明局部类时不能有访问说明符。局部类有一个很大的优势,即对外部世界完全隐藏,只有这个方法知道这个局部类的存在。
2,匿名内部类
使用局部内部类时,通常可以再进一步。假如只想创建这个类的一个对象,甚至不需要为类指定名字。这样一个类被称为匿名内部类。
如:
public void start(int interval , boolean beep)
{
var listener = new ActionListener()
{
System.out.println("aa");
}
};
var timer = new Timer(interval , listener);
timer.start();
}
如今最好使用lambda表达式来代替匿名内部类。
public void start(int interval , boolean beep)
{
var timer = new Timer(interval , event->{
System.out.println("aa");
});
timer.start();
}
3,静态内部类
有时候,使用内部类知识为了把一个类隐藏在另外一个类的内部,并不需要内部类有外围类对象的一个引用。因此,可以将内部类声明为static,这就是静态内部类。
五,异常
1,异常分类
1,所有的异常都是由throwable继承而来,但分为两个分支:error和exception。error是程序无法处理的错误,exception是程序本身可以处理的异常。
2,exception又分解为两个分支:RuntimeException,另一个分支包含其他异常。一般规则是:由编程错误导致的异常属于RuntimeException,如果程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常。
3,java语言规范将派生于Error类或RuntimeException类的所有异常称为非检查型异常,所有其他的异常称为检查型异常。
2,声明检查型异常
一个方法必须声明所有可能派出的检查型异常,而非检查型异常要么在你的控制之外(error),要么是由从一开始就应该避免的情况所导致的(runtimeException)。如果你的方法没有声明所有可能发生的检查型异常,编译器就会发出一个错误消息。
3,捕获异常
try块:用于捕获异常。
catch块:用于处理try块捕捉到的异常。
finally块:无论是否捕获或处理异常,finally 块里的语句都会被执行。
何时捕获异常,何时抛出异常?
要捕获哪些你知道如何处理的异常,而继续传播那些你不知道怎样处理的异常。(如果超类方法没有抛出异常,你就必须捕获你的方法代码中出现的每一个检查型异常,不允许在子类的throws说明符中出现超类方法未列出的异常类)