- 接口中的所有方法都自动地属于public。因此,在接口中声明方法时,不必提供关键字public;但是在实现接口的类中,必须在实现接口中的方法时把接口中的方法声明为public,如果不声明,那就默认包访问权限,编译器会报错
- 实现Comparabale接口,必须实现其中的compareTo()。并且在调用x.compareTo(y)时,若x小于y,返回一个负数;若x等于y,返回0;若x大于y,返回一个正数
- 接口中不能有实例域,接口中的数据成员都是默认为public static final的,且只能被public,static或者final修饰。代码佐证如下:
public class Test1 {
public static void main(String[] args){
I ii = new II();
System.out.println(ii.a);//ii.a会出现警告信息
}
}
interface I{
int a = 5;
void modifier();
}
class II implements I{
@Override
public void modifier() {
// TODO Auto-generated method stub
a = 6;//报错
}
}
- 接口不是类,不能使用new运算符实例化一个接口。但可以声明接口的变量,接口变量必须引用实现了接口的类对象
- 一个实现了接口的类必须实现接口中定义的方法或者将这个类本身声明为abstract
- 一个类只可以继承一个父类,可以实现多个接口
- 接口中允许有静态方法的定义和实现,该静态方法无法被继承;但是一个类的静态方法可以被子类继承甚至覆盖。代码佐证如下:
public class Test1 {
public static void main(String[] args){
II.hello();//编译报错
II.test();//注释上一行后,输出test
}
}
interface I{
int a = 5;
static void hello() {
System.out.println("hello");
}
}
class A{
static void test() {
System.out.println("test");
}
}
class II extends A implements I{
}
- 接口中的方法只能被public、abstract、default、static和strictfp修饰
- 如果接口中的方法被default修饰,则该方法可以被类继承甚至覆盖。代码佐证如下:
public class Test1 {
public static void main(String[] args){
new II().hello();//hello
II.test();//test
}
}
interface I{
int a = 5;
default void hello() {
System.out.println("hello");
}
}
class A{
static void test() {
System.out.println("test");
}
}
class II extends A implements I{
}
- 如果一个接口定义了一个默认方法,然后又在超类或另一个接口定义了同样的方法。那么子类会如何处置这个方法?
超类优先。如果超类提供了一个具体方法,在接口中同名而且有相同参数类型的默认方法将会被忽略。代码佐证如下:
public class Test1 {
public static void main(String[] args){
new A().hello();//B
}
}
interface I{
int a = 5;
default void hello() {
System.out.println("I");
}
}
class B{
public void hello() {
System.out.println("B");
}
}
class A extends B implements I{
}
接口冲突。如果一个超接口提供了一个默认方法,另一个接口提供了一个同样的默认方法,那么在实现接口的类中必须覆盖这个方法解决冲突。代码佐证如下:
/*
若把A中覆盖的hello方法注释,那么会报错
*/
public class Test1 {
public static void main(String[] args){
new A().hello();//I
}
}
interface I{
int a = 5;
default void hello() {
System.out.println("I");
}
}
interface II{
default void hello() {
System.out.println("II");
}
}
class A implements I,II{
@Override
public void hello() {
// TODO Auto-generated method stub
I.super.hello();
}
}
注意,在A中使用的是I.super.hello()
- 实现Comparator<T>接口,必须实现compare(T,T)方法
- 默认的克隆操作是浅拷贝,即并没有克隆对象中的其他对象。
- 如果一个自定义类的对象想要使用clone方法,则必须:
- implements Cloneable
- 重新定义clone方法,并指定public访问修饰符(在Object中,clone方法为protected)
- 在此,对P227注释的理解如下:由于Object中的clone方法时protected,又因为你的自定义类与Object并不是位于同一个包,所以clone方法只是对你这个类可见,但是对你的类的实例对象并不可见;也就是说你的类的所有方法都可以调用clone方法,但是你的实例对象不能调用clone方法。代码如下:
public class Test1 {
public static void main(String[] args) throws CloneNotSupportedException{
A a1 = new A();
A a2 = (A)a1.clone();//编译报错,因为clone方法只对子类以及同包的类可见,对于对象来说是不可见的
Object object = new Object();
object.clone();//编译报错,因为clone方法只对子类以及同包的类可见,对于对象来说是不可见的
}
}
class A implements Cloneable{
public A testClone() throws CloneNotSupportedException {
return (A)new A().clone();//无错,clone方法对于子类(类内部)是可见的
}
}
- 证明继承自Object的clone为浅拷贝代码如下:
/*
输出结果为:
false
true
结果表明:clone方法对于对象a1,确实是完整地复制了另外一份给a2,因此它们指向的是不同的堆
但是对于a1里面的对象array,则只是简单地拷贝了array的地址给a2.array,因此a1.array和a2.array指向的是同一个堆
*/
public class Test1 {
public static void main(String[] args) throws CloneNotSupportedException{
A a1 = new A();
A a2 = a1.clone();
System.out.println(a1 == a2);//false
System.out.println(a1.array == a2.array);//true
}
}
class A implements Cloneable{
public int array[] = {1,2,3};
@Override
public A clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return (A) super.clone();
}
}
- 将上面clone改为深复制(即对于对象中的每个对象都进行复制),代码如下:
public class Test1 {
public static void main(String[] args) throws CloneNotSupportedException{
A a1 = new A();
A a2 = a1.clone();
System.out.println(a1 == a2);//false
System.out.println(a1.array == a2.array);//false
}
}
class A implements Cloneable{
public int array[] = {1,2,3};
@Override
public A clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
A a = (A) super.clone();
a.array = array.clone();
return a;
}
}
- lambda表达式语法:(参数1,参数2,...),箭头(->)以及一个表达式。 比如:(int x,int y)->{if(x>=0) return x;else return y;}
- lambda表达式求字符串数组按字符串长度排序例子:
String[] planets = {"Mercury","Venus","Earth","Mars"};
Arrays.sort(planets,(first,second)->{return first.length() - second.length();});
System.out.println(Arrays.toString(planets));//[Mars, Venus, Earth, Mercury]
- 如果某种接口只有一个抽象方法,那么这种接口就称为函数式接口。此时可以用lambda表达式(实现接口中唯一的抽象方法)来表示这种接口的对象
- lambda表达式具体知识(没明白,先跳过)
- 使用内部类的原因:
- 内部类可以访问该类定义所在的作用域中的数据,包括私有的数据
- 内部类可以对同一个包中的其他类不可见
- 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷
- 使用外围类的引用:OutClass.this 实例化内部类对象:outObject.new InnerClass(construction parameters) 引用内部类:OutClass.InnerClass
/*
输出结果:
5
4
*/
public class Test1 {
public static void main(String[] args){
A.B b = new A().new B();
}
}
class A{
private int a = 4;
public class B{
private int a = 5;
public B() {
// TODO Auto-generated constructor stub
System.out.println(a);
System.out.println(A.this.a);
}
}
}
- 局部内部类:在方法中定义类。局部类不能使用public或private修饰。它的作用域被限定在声明这个局部类的块中。局部内部类可以使用方法中的参数,但不能修改该参数的值(方法的参数默认为final)
/*
以下代码报错,因为视图修改fianl型变量s的值
将报错行注释后输出hello
*/
public class Test1 {
public static void main(String[] args){
A a = new A();
a.hello("hello");
}
}
class A{
private int a = 4;
public void hello(String s) {
class B{
public B(){
s = "sc";//报错
System.out.println(s);
}
}
new B();
}
}
- 匿名内部类:创建一个实现了某个接口的类的新对象,且这个实现了接口的类需要就地实现接口中的所有abstract方法
/*
输出结果:
hello
*/
public class Test1 {
public static void main(String[] args){
B b = new B() {
public void hello() {
System.out.println("hello");
};
};
b.hello();
}
}
interface B{
void hello();
}
- 静态内部类无法引用其外围类的实例域
- 代理(不明白,以后再看)