Java笔记(抽象类、接口、内部类、final关键字)
(一).抽象类
- 抽象方法所在的类就是抽象类,抽象方法是在public和void中间加一个abstract,表示子类继承父类(父类是抽象类 )的方法时必须重写,否则直接报错
1.抽象方法和抽象类
2.抽象类和抽象方法的定义格式
3.抽象类和抽象方法的注意事项
-
不能实例化就是不能创建对象,抽象类是用来继承的
-
抽象类的构造方法是创建子类对象时给属性进行赋值的
-
针对,每个私有化的成员变量,要提供对应的get和set方法
-
为什么非要把相同的东西调用到父类里面的原因:就是为了统一代码
4.抽象总结
(二).接口
1.接口的定义和使用
- 创建接口的实现类对象之后要重写方法
2.接口中成员的特点
- 成员变量
- 只能是常量(成员变量),必须使用public final static三个关键词修饰
- 默认修饰符:public static final,默认的意思是就算没写,JAVA也会自动帮加上
- 因为多个子类的共有属性是抽取到父类里面的,不会抽取到接口里面,所以接口里面是不会有类似name,age这些成员变量的,而且接口是一种规则,规则是不能改变的,所以接口里面的量都是常量,会用final修饰
- static是为了调用,调用时直接 接口名点常量名称
- public公共的,在所有地方都能使用接口里的常量
- 构造方法
- 没有:因为接口里不能创建对象,而且接口也不需要给子类的成员变量去赋值
- 成员方法
- 只能是抽象方法(JDK7以前:接口中只能定义抽象方法)
- 默认修饰符:public abstract
3.接口和类的关系
1.)类和类的关系
- 继承关系,只能单继承,不能多继承,但是可以多层继承
2.)类和接口的关系
- 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 多个接口中如果有同名的方法,在子类中重写时系统也只会提示一种,所以不用全部重写,接口只是告诉有这个方法,想要用方法需要自己重写
3.)接口和接口的关系
- 继承关系,可以单继承,也可以多继承,如果是实现类实现的是最下面的子接口的话,那么需要重写所有的抽象方法
- 下图中例子:接口三继承了接口一和接口二,新建一个实现类实现接口三,那么需要把接口一二三中所有的抽象方法都重写,如果少写一个,代码会报错
4.JDK8开始接口中新增的方法
1.)接口中可以定义默认方法
-
接口中的抽象方法注意事项
-
默认方法指的是前面有default,default也是他的关键字
-
package interfaceDemo03; //接口类 public interface inter { //定义一个抽象方法,注意抽象方法没有方法体 public abstract void method(); //写一个默认方法 //默认方法不是抽象方法,所以在实现类中不强制重写,但是如果被重写,需要去掉default关键字 //default不能省略,因为不加default系统默认接口中的方法是抽象方法,那么抽象方法不能有方法体 //注意加了default后变成接口中的抽象方法就可以有方法体 public default void show(){ System.out.println("接口中的默认方法----show"); } }
-
package interfaceDemo03; //实现类 public class interimpl implements inter{ //以下为重写接口中的抽象方法,重写时idea也只会默认提示重写抽象方法 @Override public void method() { System.out.println("实现类重写的抽象方法"); } //在实现类中 重写默认方法(default),需要去掉public和void中间的关键字(default),加上就会报错 @Override public void show() { System.out.println("重写接口类中的默认方法"); } }
-
package interfaceDemo03; //测试类 public class Test { public static void main(String[] args) { //创建实现类intermpl的对象 interimpl ii = new interimpl(); //调用接口中的抽象方法(已在interimpl类中重写抽象方法) ii.method(); //调用接口中的默认方法(没有在interimpl类中重写该默认方法) ii.show(); } }
-
2.)接口中可以定义静态方法
- 子类把从父类继承下来的虚方法表里的方法覆盖了这才叫做重写
3.)接口中可以定义私有方法
- 下面第一种是给默认方法服务的(注意中间没有default修饰 )
- 下面第二种是给静态方法服务的
- 不同类型的私有方法(可以抽取本类方法中相同方法到一个不想让外界访问的私有方法中)只能去服务不同类型的方法
package interfaceDemo05;
//定义一个接口A
public interface InterA {
public default void show1(){
System.out.println("show1方法开始执行了");
show3();
}
public default void show2(){
System.out.println("show2方法开始执行了");
show3();
}
//定义一个不想让外界访问的show3方法
//中间没有加default
//普通的私有方法,给默认方法去服务
private void show3(){
System.out.println("记录程序日志");
}
}
package interfaceDemo05;
//定义一个接口B
public interface InterB {
public static void show3() {
System.out.println("show3方法开始执行了");
show5();
}
public static void show4() {
System.out.println("show4方法开始执行了");
show5();
}
//定义一个不想让外界访问的show5方法
//中间没有加default
//普通的私有方法,给静态方法去服务
private static void show5() {
System.out.println("记录程序日志");
}
}
5.接口的应用
如果一个方法中的参数是一个接口,那么在调用这个方法时候就可以传递这个接口所有的实现类对象
编译看左边运行看右边
6.适配器设计模式
-
当一个接口中抽象方法过多,但是我只使用其中一部分时候,就可以用适配器设计模式
-
package interfaceDemo06; //定义一个有很多抽象方法的接口 public interface Inter { public abstract void method1(); public abstract void method2(); public abstract void method3(); public abstract void method4(); public abstract void method5(); public abstract void method6(); public abstract void method7(); public abstract void method8(); public abstract void method9(); public abstract void method10(); }
-
package interfaceDemo06; //定义一个适配器 public abstract class InterAdapter implements Inter{ //对接口里的所有方法先进行空实现,即没有方法体 //因为适配器中的方法都是空实现,创建适配器的对象没有意义,所以一般把接口定义成abstrac,防止外界创建适配器的对象 //让适配器实现接口,让子类继承适配器 @Override public void method1() { } @Override public void method2() { } @Override public void method3() { } @Override public void method4() { } @Override public void method5() { } @Override public void method6() { } @Override public void method7() { } @Override public void method8() { } @Override public void method9() { } @Override public void method10() { } }
-
package interfaceDemo06; public class interimpl extends InterAdapter{ //定义好适配器后,就不需要实现接口,直接继承中间的interadapter //那么在这个类中,需要用到哪个方法,就重写哪个方法 //也就是说给接口设置了一个适配器,只让子类去重写利用特定的方法 @Override public void method5() { System.out.println("只用了第五个方法"); } }
-
package interfaceDemo06; //测试类 public class Test{ public static void main(String[] args) { //想要测试方法,需要先new一个类的对象,再用对象调用这个类的方法 interimpl s = new interimpl(); s.method5(); } }
-
如果实现类还有爹,那么让中间类(适配器)继承这个爹,实现类继承中间类(适配器)即可
- 实现类–中间类–父类
(三).内部类
- 初识内部类
可以在外部其他类中定义内部类,并调用内部类的方法
注意右边注释
- 外部类的对象创建需要在主函数中
- 内部类的创建对象在外部类中
1.成员内部类
1.)成员内部类如何书写
- private修饰内部类后只能在外部类中使用,创建内部类的对象在内部类之外,外部类之内,一单私有,那么不能在其他类创建对象
- 前面什么都不写就和成员变量一样,就是默认权限,只能在本包(pckage)中使用
- protected是在本包中和其他包的子类中使用
- public表示可以在其他任何地方创建内部类的对象
- static修饰,表示静态内部类
2.)如何创建成员内部类的对象
Outer.Inner oi = new Outer().new Inner;
//用外部类变量去调用内部类变量,把地址赋给oi
//链式编程
//Sout(new Outer().name)
- 内部类被private修饰,那么在外界就不能直接创建内部类的对象
- 第一种解决方法:把private改成public
- 第二种解决方法:在外部类中定义一个提供内部类的方法,方法当中返回内部类成员,外界直接通过方法去获得内部类的对象
- 第一种解决方法:把private改成public
3.)成员内部类如何获取外部类的成员变量
public class outer{
private int a =10;
class Inner{
private int a 20;
public void show(){
int a 30;
System.out.println(Outer.this.a);//注意此处调用外部类成员变量的方法 Outer.this.a
System.out.println(this.a);//调用内部类方法外的成员变量
System.out.println(a);//就近原则,调用方法内部的成员变量
}
}
}
public class Test{
public static void main(string[]args){
//创建内部类的对象,并调用show方法
Outer.Inner oi new outer().new Inner();
oi.show();
}
}
- 内部类对象里面有一个 Outer this用来记录外部类对象的地址,Outer.this.a取得就是外部类对象的值
- 上述第四点是访问外部类的成员变量
2.静态内部类
-
成员内部类的一种特殊情况
-
当成员内部类前面用static修饰时,这个类就成为了静态内部类
-
因为是静态,所以不用创建键外部类的对象,直接用外部类的类名就可以直接调用
-
注意下图:静态类的静态方法中直接打印外部类的成员变量,不需要创建对象,直接打印即可;而静态类的静态方法中打印外部类的非静态变量,需要先在静态方法中创建外部类的对象,再用对象点上外部类的成员变量才能打印
-
创建静态内部类的变量
-
只要是静态的东西,都可以用类名点直接获取(new Outer.Inner)
-
以下为oi直接调用静态类中的非静态方法
-
以下为调用静态类的静态方法的过程,一路点到底
-
当然调用静态方法时可以直接用创建的oi调用show2,但idea不会提示,因为idea不建议
3.局部内部类
1.将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
2.外界是无法直接使用,需要==在方法内部创建局部内部类的对象==并使用。
3.该类可以直接访问外部类的成员,也 可以访问方法内的局部变量。
-
注意private public 默认 final只能修饰成员变量(成员变量是定义在类里面的变量),不能修饰局部变量(局部变量是定义在方法里面的变量)
-
总结包含关系就是 外部类—(外部类的方法中的类)局部内部类
-
局部内部类(Inner)里面有局部变量(name、age),外部类有成员变量(b,Inner类),局部内部类(Inner)可以直接访问(自己局部内部类的)局部变量(name、age)和(外部类的)成员变量(b),如果想访问自己(局部内部类)的变量(name、age),需要在自己外面,自己的方法里面创建自己的对象(i),再在方法里面,自己外面调用的局部变量(i.name、i.age)
4.匿名内部类
-
实现关系:Swim是一个接口,后面大括号里面对他是实现关系,而不是继承关系,后面紫色大圆圈圈起来的部分就是匿名内部类,注意后大括号后面的分号;
-
方法的重写:后面匿名内部类实现了接口swim,实现接口就要重写接口里面的所有方法;
-
创建对象:new关键字创建的就是后面大括号里面的内容;
-
Swim后面的小括号表示用的是没有参数的空参构造去创建的
-
整体其实是new出来的对象,正真的匿名内部类是后面大括号的一堆
- Animal是一个类,匿名内部类对它是继承关系,而不是实现关系。
- 方法的重写:既然是继承关系那么就要重写父类里的所有方法。
- 创建对象:new创建了大括号里的对象
- 整体其实是new出来的对象,正真的匿名内部类是后面大括号的一堆
-
如果类只使用一次,那么就不应该去专门定义一个类而且去创建一个这个类的对象,只需要用匿名内部类去当做参数传递给函数即可,如上图,把创建的匿名内部类对象当做method函数的参数传递进去,就相当于实现了多态
-
拓展,既然整体相当于一个对象(这个对象是大括号的匿名内部类的对象),那么就可以把他(这个new的整体可以理解为Swim接口的实现类对象)赋值给Swim类型的变量,或者用这个对象调用方法(这个对象就是后面大括号创建的对象,所以他可以点上自己类里面的方法去实现自己类中的方法)
-
链接:接口创建实现类对象(重写了接口中的方法)(接口多态)
在实际开发中,我们常常遇到这样的情况:一个接口/类的方法的某个实现方式在程序中只会执行一次,但为了使用它,我们需要创建它的实现类/子类去实现/重写。此时可以使用匿名内部类的方式,可以无需创建新的类,减少代码冗余。
//匿名内部类可以用在具体类、抽象类、接口上,且对方法个数没有要求。
//举例说明:设存在具体类Class01,抽象类AbstractClass01,接口Interface01
//具体类
public class Class01 {
public void show(String s){
System.out.println("啦啦啦");
}
}
//抽象类
public abstract class AbstractClass01 {
abstract void show(String s);
}
//接口
//如果实现类Interface01Impl全程只使用一次,那么为了这一次的使用去创建一个类,未免太过麻烦。我们需要一个方式来帮助我们摆脱这个困境。匿名内部类则可以很好的解决这个问题。
//public interface Interface01 {
// void show();
//}
//public class Interface01Impl implements Interface01{
// @Override
// public void show() {
// System.out.println("I'm a impl class...");
// }
//}
public interface Interface01 {
void show(String s);
}
public class TestInner {
public static void main(String[] args) {
//重写具体类的方法
new Class01(){
@Override
public void show(String s) {
System.out.println("我是一个" + s);
}
}.show("具体类");
//重写抽象类的抽象方法
new AbstractClass01(){
@Override
void show(String s) {
System.out.println("我是一个" + s);
}
}.show("抽象类");
//实现接口的抽象方法
new Interface01(){
@Override
public void show(String s) {
System.out.println("我是一个" + s);
}
}.show("接口");
}
}
(四).final关键字
1.final
关键字的使用
在Java
中声明类、属性和方法时,可使用关键字final
来修饰。
final
标记的类不能被继承。final
标记的方法不能被子类复写。final
标记的变量(成员变量或局部变量)即为常量,只能赋值一次。
2.final
关键字修饰类、成员变量和成员方法
1.)final
类
final
用来修饰一个类,意味着该类成为不能被继承的最终类。出于安全性的原因和效率上的考虑,有时候需要防止一个类被继承。例如,Java
类库中的String
类,它对编译器和解释器的正常运行有着很重要的作用,不能轻易改变它,因此把它修饰为final
类,使它不能被继承,这就保证了String
类的惟一性。同时,如果你认为一个类的定义己经很完美,不需要再生成它的子类,这时也应把它修饰为final
类。 定义一个final
类的格式如下:
final class ClassName{...}
**注意:**声明为final
的类隐含地声明了该类的所有方法为final
方法。
下面的结论是成立的:声明一个类既为abst\fract
,又为final
是非法的,因为抽象类必须被子类继承来实现它的抽象方法。下面是一个final
类的例子:
final class A{...}class B extends A{//错误!不能继承A...}
2.
)final``修饰成员变量 变量被声明为final
后,成为常值变量(即常量),一旦被通过某种方式初始化或赋值,即不能再被修改。通常static与
final`一起使用来指定一个类常量。例如:
static final int SUNDAY=0;
把final
变量用大写字母和下划线来表示,这是一种编码规定。
3.
)final``修饰成员方法 用final
修饰的方法为最终方法,不能再被子类重写,可以被重载。 尽管方法重写是Java
非常有力的特征,但有时却需要避免这种情况的发生。为了不允许一个方法被重写,在方法的声明中指定final
属性即可。例如:
class A{final void method(){}}class B extends A{//定义A类的一个子类Bvoid method(){}//错误,method()不能被重写}
该例中,因为method()
方法在A
中被声明为final
,所以不能在子类B
中被重写。如果这样做,将导致编译错误。 方法被声明为final
有时可以提高性能:编译器可以自由地内联调用它们,因为它“知道”它们不会被子类重写。
class A{…}class B extends A{//错误!不能继承A…}
`2.`)final``修饰成员变量 变量被声明为`final`后,成为常值变量(即常量),一旦被通过某种方式初始化或赋值,即不能再被修改。通常static`与`final`一起使用来指定一个类常量。例如:
static final int SUNDAY=0;
把`final`变量用大写字母和下划线来表示,这是一种编码规定。
`3.`)final``修饰成员方法 用`final`修饰的方法为最终方法,不能再被子类重写,可以被重载。 尽管方法重写是`Java`非常有力的特征,但有时却需要避免这种情况的发生。为了不允许一个方法被重写,在方法的声明中指定`final`属性即可。例如:
class A{final void method(){}}class B extends A{//定义A类的一个子类Bvoid method(){}//错误,method()不能被重写}
该例中,因为`method()`方法在`A`中被声明为`final`,所以不能在子类`B`中被重写。如果这样做,将导致编译错误。 方法被声明为`final`有时可以提高性能:编译器可以自由地内联调用它们,因为它“知道”它们不会被子类重写。
标签:Java,重写,void,接口,public,抽象类,方法,final
From: https://blog.csdn.net/weixin_73749601/article/details/144521632