ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

接口 内部类

2021-01-19 21:31:48  阅读:136  来源: 互联网

标签:pp 内部 void 接口 public static class


接口 内部类

什么是接口

在Java中不直接支持多继承,因为会出现调用的不确定性,所以Java将多继承机制进行改良,在Java中变成了多实现。一个类只能有一个直系双亲类,一个类可以实现多个接口,一个接口可以继承多个接口

interface IA{}
 interface IB{}
interface IC extends IA,IB{}//正确的,其中IC中的方法等于IA+IB
 class A implements IA,IB{}
IA a=new A();
 IB b=new A();
  • 没有构造器方法,不能定义静态或者非静态代码块
 
public interface IA{
public IA(){} //语法报错
}
  • 没有属性,只能定义常量
public class Test {
public static void main(String[] args) {
System.out.println(IA.name);
System.out.println(B.name);
//常量可以直接使用
//实现类也可以直接访问常量
}
}
interface IA {
//private int age;语法报错,提示信息为Illegal modifier for the interface field
IA.name; only public, static & final are permitted
String name = "liuxin";// 接口中只能定义常量,不能定义属性,默认限定词public static
final,自定义限定词不能冲突
}

class B implements IA{}
//访问常量既可以通过接口IA和实现类B名称的方式直接访问,例如B.name。也可以通过B对象的方式进行访,例如new B().name
  • 可以包含抽象方法,也可以没有抽象方法
nterface IA1 {
 }// 这个接口中没有包含任何抽象方法。如果一个接口中没有定义抽象方法,这种接口也叫做旗标接口、标志接口
 class A1Impl implements IA1 {
 }
interface IA2{//接口的限定词同类定义一致
int ee();//抽象方法,默认public abstract int ee();
public void pp();//方法的限定词可以是public, abstract, default, static,前面的public可以省略,如果不写默认public
public abstract void cc();//这里abstract可以省略,默认就是abstract
//在JDK1.8中引入特殊关键字default,允许在接口中提供方法的默认实现
public default void dd(){
//这个方法的调用时必须有实现类,否则无法创建对象,例如newIA2()语法错误,也允许在实现类中覆盖定义
System.out.println("dddd....");
 }
 //在JDK1.8中允许在接口中定义静态方法
public static void ff(){
//这个静态方法可以通过接口名称直接调用IA2.ff(),同时允许在实现类中重新定义,但是不能通过IA2 a=new AImpl();a.ff()的方式进行调用
System.out.println("ffffff");
}
}
  • 接口允许多重继承,也允许一个类实现多个接口
public class Person {
 public static void main(String[] args) {
 IC cc=new CImpl();
 cc.pp();
 }
 }
 interface IA{
public default void pp() {
System.out.println("this is IA.pp() default");
}
}
interface IB{

public default void pp() {

System.out.println("this is IB.pp() default");
}
 }
 //因为在两个父接口中都定义了pp方法的默认实现,则在子接口无法确定到底使用哪个,所以要求子接口必须明确说明

interface IC extends IA,IB{
 @Override
 default void pp() {
System.out.println("this is IC.pp() default");
 IA.super.pp();//调用IA接口所定义的pp方法
 IB.super.pp();
}
 }
 class CImpl implements IC{}
//在子接口中覆盖定义
public class Person {
 public static void main(String[] args) {
 IA cc=new CImpl();
 cc.pp();
 }
 }
 interface IA{

public default void pp() {

System.out.println("this is IA.pp() default");

}
}

interface IB{

public default void pp() {

System.out.println("this is IB.pp() default");

}
 }
 //报错的原因是IA和IB接口中有相同的方法定义,同时又有默认实现,则CImpl类不知道使用哪个默认实现,所以要求类中必须明确说明
class CImpl implements IA,IB{
 @Override
 public void pp() {
 System.out.println("可以定义自己的逻辑");
 IA.super.pp();//也允许调用某个接口中的默认实现
IB.super.pp();
}
}
  • 抽象方法必须在实现类中提供实现
class A2Impl implements IA2{
//在实现类中必须实现接口中的所有抽象方法,否则当前类只能是抽象类
 public int ee() {
 return 0;
 }
 public void pp() {
System.out.println("A2Impl....");
 }
 public void cc() {

System.out.println("A2Impl.....");
}
//dd方法由于在接口中有默认实现,所以可以不用重新定义,也允许重新定义
}
  • 可以使用default关键字给抽象方法提供默认实现,有默认实现的方法在实现类中可以重新定义,也可以不重新定义

报错原因:Java中不支持类的多重继承,一个类只能有一个双亲类

接口允许多重继承

一个类在继承另一个类的同时,还可以实现多个接口

public class Person {
 public static void main(String[] args) {
 IA a1=new AImpl();
 B a2=new AImpl();
 a1.pp();
 }
 }
 interface IA{

public void pp();
}
class B {
public void pp() {

System.out.println("this is B.pp()");

}
 }
 class AImpl extends B implements IA{//AImpl类是通过继承B类实现了对接口IA中的抽象方法提供实现
 }
public class Person {
 public static void main(String[] args) {
 IA a1=new AImpl();
 a1.pp();
 IB a2=new AImpl();
a2.pp();
 }
 }
 interface IA{

public void pp();

}

interface IB {

public default void pp() {

System.out.println("this is B.pp()");

}
 }
 class AImpl implements IA,IB{
//不能因为IB中针对pp方法提供了默认实现,所以不在实现类中定义pp方法
 @Override
 public void pp() {

System.out.println("添加的新的处理逻辑");
//IA.super.pp();因为IA接口中并没有提供pp的默认实现,所以不允许这样调用
IB.super.pp();
}
}

接口允许多重继承

interface IA1{
public void p1();
 }
 interface IA2{
public void p2();
}
interface IC extends IA1,IA2{
public void p3();
//继承父接口的同时也允许自定义方法
}//可以继承多个父接口,此时IC中实际有3个抽象方法

类是单根继承,不允许继承多个父类
允许一个类实现多个接口,但是每个接口的抽象方法都必须提供实现,否则是抽象类。提供的实现也可以是继承

public class A1{

public void p1(){}
 }
 public class A2 extends A1 implements IA1,IA2{
public void p2(){}
}
public abstract class A3 extends A1 implements IA1,IA2{}//因为p2方法没有实现

接口的出现避免了单继承的局限性,这样定义C接口则拥有A+B的所有定义,可以使用A和B接口以及父类D声明变量类型,直接new T。但是约束时,用谁声明变量编译器系统识别就是谁这种类型,也就意味只能调用识别类型中的方法,不能调用其他方法

interface A{

public void p1();
 }
 interface B{

public void p2();
 }
 interface C extents A,B{}

class D{

public void abc(){}
 }
 class T extends D implements C{

public void p1(){}

public void p2(){}
}
 D d=new T();这里只能直接调用abc方法,如果使用其他方法则需要进行类型转换
 A a=new T();这里只能直接调用A接口中声明的方法p1
 B b=new T();这里只能直接调用B接口中声明的方法p2
 C c=new T();

声明接口的语法

访问修饰符 interface 接口名{}一般建议接口名称使用形容词
  • 如果定义public接口,则规则和定义public类一致,要求接口名称和文件名称一致
  • 外部的接口只能使用public、默认这两个范围限定词;如果定义内部接口则可以使用4大范围限定词
  • 接口实际上提供了同一的操作界面(方法),如果是JDK1.8-版本则一个方法也不实现,等待某类或某几个类去实现它的方法【接口中的所有方法必须是抽象的】。如果使用的是JDK1.8+允许使用default在接口中定义默认实现,这个实现允许在实现类中重新定义覆盖
public class Test1 {

public static void main(String[] args) {
 IA2 a2=new A2Impl();
 a2.pp();
}
}
interface IA2 {
default void pp(){ //通过defaul在接口中定义方法的默认实现,则在实现类中可以覆盖定义,也可以继承使用
 System.out.println("this is pp....");
 this.ff();
}

void ff();
}
class A2Impl implements IA2{

public void ff() {

System.out.println("this is ff...");

}
}
  • default默认方法实现使用的限制
public class Test1 {

public static void main(String[] args) {

IA2 a2 = new A2Impl();

a2.pp();

}
 }
 interface IA2 {

default void pp() {

System.out.println("this is No2 pp....");

}
 }
 interface IA3 {

default void pp(){

System.out.println("this is No3 pp");

}
 }
 class A2Impl implements IA2, IA3 {//如果IA2中有一个default实现的方法和IA3中的方法一致,则必须在实现类中重新定义

public void pp() {
IA2.super.pp();//调用IA2接口中的pp方法的默认实现
 IA3.super.pp();

}
  • 接口中没有属性,只能定义常量,它提供一些常量,实现它的类可以共享这些常量
  • 接口可以给出访问控制符,用public修饰的是公共接口,到处可见;如果定义接口没有范围限定词,则只能在同包中访问

接口中只能定义常量和抽象方法

  • 这是JDK1.8以前版本的规则,不是最新的
    接口中只能定义公共的常量,接口中的属性- 默认是public static nal类型的,必须是public static nal类型的
interface IA{
String name="yanjun";//这里实际上是常量定义,不是属性,它的限定词是public static final String name="yanjun",必须在声明的同时进行赋值
 }
 //在接口中不能定义静态块
 //接口中不能定义构造器
  • 接口中只能定义公共的抽象方法, 只有在JDK1.8+中可以使用default关键字定义方法实现。接口中的方法默认是public abstract类型的,而且必须是public abstract类型的。只有在JDK1.8+中可以使用default关键字定义方法默认实现,同时允许在实现类中覆盖重新定义
  • 接口不能被实例化,只能通过实现类所实现,但是可以用于声明变量的类型。
    接口 变量名=new 实现接口类();
  • 接口没有构造函数
  • 接口中的抽象方法必须在非抽象子类中提供实现,这个实现可以是继承来的
interface IA2 {

public void pp();

}
class A2 {
 public void pp() {
 }

}
 class B2 extends A2 implements IA2 { //这里的pp方法的实现是从父类中继承来的
 }

一个类实现接口的语法

class 类名称 implements 接口名称
{}
  • 接口抽象方法的默认修饰符为public,在实现接口时必须用public关键字在方法头上说明
interface IA2 {
void pp();
 }
 class B2 implements IA2 {
 void pp() {
 }
//语法报错,因为IA2接口中的方法为public abstract
}
  • 一个接口可以被多个子类实现。一个子类还可以实现多个接口

类实现接口

  • 一个类在实现某接口的抽象方法时,必须使用完全相同的方法头public
  • 如果一个类实现多接口,用逗号隔开
  • 如果一个类实现了声明相同方法的两个接口,则被多个接口共用
public class Test1 {

public static void main(String[] args) {
 IA2 a2=new B2(); a2.pp();
 IA3 a3=new B2(); a3.pp();

}
 }
 interface IA2 {

void pp();
}
 interface IA3{
 void pp();
 }
class B2 implements IA2,IA3 {

public void pp() {
System.out.println("this is B2.pp()");
}
}
  • 类在实现接口时可以定义它自己的附加成员,这也是最常见的形式
public class Test1 {
2
public static void main(String[] args) {
3 IA2 a2=new B2();
4 a2.pp();//这里不能直接调用B2实现类中的其它方法,如果需要调用则应该进行强制类型转换
5 ((B2)a2).dd();
6
7
}
}

interface IA2 {

void pp();
}

 class B2 implements IA2 {
 public void pp() {

System.out.println("this is B2.pp()");
}

 private int age=100;
 public void pp(int k){

System.out.println("this is pp(int)");
}
public void dd(){
System.out.println("this is dd()");
}
}
  • 如果一个类不完全实现接口的所有方法,必须把类定义成abstract类型的类,任何继承该类的子类必须实现该
    接口

接口中常量

  • 可以为多个接口的实现类共享常量
public class Test1 {

public static void main(String[] args) {
 System.out.println(IA2.PI);//可以直接使用
 A3 a=new A3();
 a.setR(4);

System.out.println(a.getArea());

}
 }
 interface IA2 {

double PI=3.1415;
 }  class A3 implements IA2{
 private double r;
 public double getArea(){

//在实现类中也可以直接使用
return PI*r*r;
 }
 public void setR(double r) {

this.r = r;

}
}
  • 只需在接口中定义并赋值,此后不能再修改
  • 在类中说明是接口的实现类,就可以使用该接口的常量了

一个对象往往有多重身份

  • Java中一个子类只能继承一个父类 (不能表示)
  • java中一个类可以实现多个接口。(可以表示
class 类名称 implements 接口1,接口2, ... {}
  • 通过继承和运行时多态的双重机制,可以定义一个被很多不同却有关的对象类型的运用的一致的接口
  • 维持抽象接口,甚至不需要重新编译,就可以调用新类的实例
public void 出差(会飞的
obj){
obj.起飞(); ...}
 调用的时候可以传入不能类型的对象
 出差(new 飞机());
--- 出差(new 鸟());

接口的特殊特征

  • 一个类只能有一个父类!
  • 一个类可以实现多个接口!
  • 一个接口可以继承多个接口
interface 接口名 extends 接口名称1 ,父接口名称2 , ...{}

接口的作用

  • 统一访问
接口 obj=new 实现1(); 可以还有实现2,实现3
obj只能调用接口中定义的方法

  • 解耦 通过接口可以隔离具体实现
    解耦就是 在使用者 和 实现者 之间没有关系。 无论实现者如何改变实现,对于使用者使用不会变化

接口和抽象类的异同点

  • 相同点:都是不断向上抽取而来的
  • 不同点:
  • 抽象类需要被继承,而且只能单继承
  • 接口需要被实现,而且可以多实现
  • 抽象类中可以定义抽象方法和非抽象方法,子类继承后可以直接使用非抽象方法
  • 接口中只能定义抽象方法,必须由子类去实现;JDK1.8+中允许接口中的方法有默认实现,实现类中可以直接使用默认实现,允许覆盖定义
  • 抽象类的继承是is a关系,在定义该体系的基本共性内容
  • 接口的实现是like a关系,在定义体系额外功能
  • 接口中只能定义常量,而且必须被初始化,抽象类中可以定义属性,允许在声明时直接初始化,也可以不初
    始化,同时允许定义常量
    接口中的方法必须全部是抽象的(JDK1.8+版本中可以通过default关键字定义方法的默认实现,允许定义静态方法),抽象类中可以有抽象方法也可以有普通方法
public class Test1 {

public static void main(String[] args) {
 IA2.pp();
 A2Impl.pp();

IA2 a2 = new A2Impl();

a2.pp();// 语法报错

}
}


interface IA2 {

public static void pp() {

System.out.println("IA2 static....");

}
}

 class A2Impl implements IA2 {
 public static void pp() {

System.out.println("A2Impl static..");

}
}
public class Test2 {

public static void main(String[] args) {
 Fa ff = new Son();
 ff.pp();

}
 }
 class Fa {

public static void pp() {

System.out.println("Fa static....");

}
 }
 class Son extends Fa {

public static void pp() {

System.out.println("Son static....");

}
}

public void pp();在接口中是抽象方法,但是如果public void pp(){}语法错误,在JDK1.8+版本中可以使用public default void pp(){}就合法了

如果一组相关的类中有公共的方法和特殊的方法,可以使用抽象类,在抽象类中固化公共的方法,而无需具体子类重复实现;但是在抽象类中无法实现的方法可以延迟到子类中再实现。例如排序器BubbleSorter,其中抽象类BubbleSorter固化了所使用的冒泡排序算法,而将无法实现的bigger比较算法延迟到BubbleSorter的子类PigSorter中实现,同时PigSorter中也不需要重新定义排序算法

最佳软件开发实践:先定义接口规范调用方法,在使用抽象类实现接口定义公共方法,最后再定义具体子类实现所
有的方法

内部类

一个类或者接口定义在另外一个类或者接口的内部

public class A1{//外部类
class B1{}//内部类
interface C1{}//内部接口
}

将一个类定义置入另一个类定义中,这就叫作“内部类”

  • 内部类之外的类称为外部类
  • 内部类的名称必须区别于它所在的外部类,和其它类之间没有要求
//内部类的全名叫做[外部类名称$内部类名称]
 public class A1 {
 public class A1{}
 class B1{}
 }
 class B1{}
  • 内部类可以访问其外部类的所有变量和方法
 
public class A1 {//外部类的范围限定词只能是public或者默认package

private String name;

public class B1 {

//内部类的范围限定词可以是4种
public void pp() {
 System.out.println(name);
//可以直接访问外部类的成员
System.out.println(A1.this.name);//这里的A1.this用于表示A1类对象
 A1.this.name="ffff";
 // System.out.println(this.name);报错的原因是this用于指代当前类的对象,当前类
B1中并没有属性name

pp();

//可以直接访问外部类的成员
A1.this.pp();

}
 }
 private void pp(){}

}
  • 外部类不能直接访问内部类的实现细节,可以通过创建内部类对象的方式直接访问,不受限定词的影响

  • 内部类比外部类多了private/protected/static三个修饰符,这三个修饰符不能用在外部类上

  • 非静态内部类不能拥有静态成员,静态内部类则没有这个限制

public class A{

protected class B1 {
 private int age = 99;
 {
 private static String password="123456";//非静态内部类中不能包含静态属性
 static{
 public B1() {//允许定义构造器和析构器方法
 }
 public static void hh(){} //非静态内部类中不允许包含静态方法

}//允许包含非静态代码块
}//非静态内部类中不允许包含静态代码块
}
}

内部类的作用

  • 内部类提供更好的封装
    内部类可以直接访问外部类的私有成员,外- 部类不能直接访问内部类的成员
  • 匿名内部类适合用于创建仅仅使用一次使用的类

内部类相关的设计

  • 分析事物时发现该事物描述还有事物,而且这个事物还在访问被描述事物的内容
    例如牛和牛腿
  • 如果一个事物离开另外一个事物后则没有任何意义,这种情况下建议使用内部类,不允许其他类访问
  • 内部类能直接访问外部类中成员,是因为内部类持有了外部类的引用,即外部类名.this

内部类分类

在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
内部类实际拥有外部类的一个引用,在构造函数中将外部类的引用传递进来。

非静态内部类

public class A1{

protected class B1{}//静态内部类是protected static class B1{}
}
  • 在创建非静态内部类对象时,一定要先创建起相应的外部类对象
public class A1 {

public static void main(String[] args) {
 B1 b = new B1();
 B1.C1 cc = b.new C1();
//内部类的写法为[外部类名.内部类名],否则需要import com.yan.B1.C1;则可以直接使用C1类。至于C1类是否可见取决于C1类的范围限定词

System.out.println(cc);
}
}
class B1 {

public class C1 {

}
}
  • 在任何非静态内部类中,都不能有静态数据、静态方法或者又一个静态内部类
//语法错误
 public class A1{

public class B1{

public static String name="yan";//语法错误,除非B1类是静态内部类
static class
B1{}
 static{}//语法错误
 public static void pp(){}//语法错误
 public static class C1{}//语法错误
}
}
  • 注意内部类的可见性范围限制
  • 访问方法:直接访问外部类中内部类中的成员
class B1 {
 private String pwd;
 private void dd(){}
 protected class C1 {
 private String name;
 private void pp(){
 System.out.println(pwd);//内部类可以直接访问外部类中的私有成员
 //另外的写法
 dd();

//另外的写法

B1.this.pwd
B1.this.dd();
}
 }
 public void ee(){
 //如果需要访问内部类中的成员,则必须首先创建内部类对象
 C1 cc=new C1();
 //通过构建的内部类对象则可以访问内部类中的私有成员
 cc.name="abc";
 cc.pp();
}
}
  • 外部类.内部类 in=new 外部类().new 内部类();
 
public class A1 {

public static void main(String[] args) {

B1 b = new B1();

B1.C1 cc=b.new C1();//内部类是否可以访问到,取决于内部类上的范围限定词

}
}

class B1 {

class C1{}
}
  • in.内部类方法();
public class A1 {

public static void main(String[] args) {
 B1 b = new B1();
 B1.C1 cc=b.new C1();
 cc.pp(); //是否可以访问pp方法取决于pp方法的范围限定词

}

}
class B1 {

class C1{

public void pp(){}

}

}
  • 注意内部类的可见性范围限制
class B1 {
private class C1{//注意这个C1类只能在B1类中进行使用,其它位置不可见
public void pp(){}
}
}

问题:

public class A1 {

public A1(){

System.out.println("aaaaa");
 }
 public static void main(String[] args) {

new A1();//创建外部类对象和内部类无关,创建外部类对象并不会自动创建内部类对象

}
class C1 {

public C1() {

System.out.println("dddd");

}

}
}

静态内部类

public class A1{

public static class B1{}//静态内部类
}
  • 静态内部类中,可以有静态数据、静态方法或者又一个静态内部类
class B1 {

static class C1 {// 在静态内部类中才可以定义静态成员
 private static int age = 123;
 private String pwd="123456";//同时允许定义非静态成员
 static {

System.out.println("c1 static...");
 }
 public static void pp() {

System.out.println("c1 static pp...");
 }
 public void ff(){//同时允许定义非静态成员
 }
 static class D1{}
 class E1{}

}
}

如何使用静态内部类

public class A1 {

public static void main(String[] args) {

B1.C1 cc = new B1.C1();//不需要构建外部类对象,就可以直接创建静态内部类对象,但是是否可见取决于范围限定词
 B1.C1.pp();//可以直接访问静态内部类中的静态成员,但是是否可见取决于范围限定词
 cc.ff();

}

}

问题

public class A1 {

public static void main(String[] args) {

B1.C1 cc = new B1.C1();

}
}

class B1 { //外部类
static{

System.out.println("b1 static...");
 }
 private B1() {
System.out.println("bbbbbb");
 }
 static class C1 {// 在静态内部类中才可以定义静态成员

public C1() {

System.out.println("cccccc");
 }
 static {

System.out.println("c1 static...");
 }
 //输出只有
 //c1 static...类加载完成后自动执行,不会执行外部类的静态块b1 static..."
 //cccccc构建静态内部类对象和外部类无关,没有要求必须先构建外部类对象
  • 静态内部类中,也可以有非静态数据、非静态方法或者又一个非静态内部类

  • 静态内部类中,不能访问外部类的非静态成员,这是由Java语法中【静态方法不能直接访问非静态成员】所限定

class B1 {
 private static String name1 = "yan1";
 private double salary = 123.456;

static class C1 {
 private static int age = 123;
 private String pwd = "abc";

public static void pp() {
 System.out.println(age);// 静态方法只能访问静态成员
 // System.out.println(this.age);在靜態方法中不允許使用this或者super
 // System.out.println(pwd); 语法报错,因为静态方法只能访问静态成员
 System.out.println(name1);// 静态内部类中可以直接访问外部类中的静态成员
 dd();
 // System.out.println(salary);语法报错,因为静态方法只能访问静态成员

}

public void fff() {
 System.out.println(this.age);
 System.out.println(pwd);//当前类中的非静态成员

System.out.println(name1);// 不允许使用B1.this或者this.进行访问,不允许使用B1.this是因为构建C1类对象时没有要求必须构建外部类对象

// System.out.println(salary);报错的原因是构建构建C1类对象时没有要求必须构建外部类对象
 dd();
 // ee();z直接访问ee方法报错,构建构建C1类对象时没有要求必须构建外部类对象
}
}

 private void ee() {
 }
 private static void dd() {
 }
 }

问题1:

class B1 {

static class C1 {

}
}

 构建内部类对象的方法:
 B1.C1 cc = new B1.C1();
 以下创建方法错误:
 B1 b = new B1();

B1.C1 c = b.new C1();

问题2:

public class A1 {

public static void main(String[] args) {

B1.C1 bcc=new B1.C1();
}
}

class B1 {
 private static D1 dd=new D1();
 static {

System.out.println("B1 static....");
 }
 static class C1 {
 private static E1 dd=new E1();
 static {

System.out.println("C1 static...");

}

}
 }
 //这里执行会发现B1类的静态代码块和静态属性并没有执行处理,所以要理解外部类实际上是内部类的一个名空间。加载内部类时实际上并没有加载外部类----重点

局部内部类

可以将内部类定义在一个方法或者一个代码块内

public class A1 {
2
private int age = 123;
3
4
public static void main(String[] args) {
5
A1 aa = new A1();
6
}
7
8
public void pp() {
9
Date birth = new Date();
10 // B1 bb=new B1();语法错误,要求局部内部类必须先定义后使用
11 class B1 { // 局部内部类,只能在所在的{}范围中使用,具备内部类的范围限定词和临时变量一致,只能添加final或者abstract

public void ff() {
 System.out.println(age);
 A1.this.age = 555;// 可以直接访问外部类中的成员
 System.out.println(birth);
 // 语法报错,在局部内部类中使用外部的临时变量,则外部临时变量必须是final的,只是final可以省略
 // birth = new Date();针对引用类型修改地址是不允许,但是可以修改属性
System.out.println("B1...ff()");

}

}

B1 bb = new B1();

}
}

问题:

public class A1 {

private int age = 123;


public static void main(String[] args) {

A1 aa = new A1();

}

public void pp() {
static class B1 {//局部内部类不能是static
 static int age = 999;//不允许包含静态成员
 static{}

public static void ff(){}

}

}
}

注意:局部内部类需要先定义后使用,不能是先使用后定义

匿名内部类

匿名内部类就是内部类的简写格式

public class A1{

public void pp(){

class B1 extends C1{}
//定义内部类时实际上允许继承于其他类或者实现特定接口
 }
 }
 //简化写法
 public class A1{

public void pp(){

new C1(){};//原始命名类的写法class B1 extends C1{}
new B1();
}
}

下面写法使用较多

public class A1 {

public void pp(){

Object obj=new Object(){
 @Override//覆盖父类中定义的方法
 public String toString() {

return ("anon inner class ... ff");

} };
System.out.println(obj.toString());//调用匿名内部类中覆盖定义的方法

}
}

匿名内部类的前提是必须继承或者实现一个外部类或者接口

new interfacename(){......};
 new superclassname(){......};

 如果父类中没有无参构造器,则()中应该有对应的参数
 public class A1 {
public void pp(){
 new B1(20){
 };

//因为B1类中没有无参构造器,必须直接传入参数
}
 }
 class B1{
 private int age;
 public B1(int age){

this.age=age;

}
}
  • 匿名内部类由于没有名字,所以它没有构造函数
  • 如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数
  • 不能定义静态成员

匿名内部类的使用场景

当方法参数是接口类型时,而且接口中的方法不超过三个,可以用匿名内部类作为实际参数进行传递

public interfce IA{

public void cc();
}

public class B{

public void pp(IA a){
}
}

public class Test{

public static void main(String[] args){
 B b=new B();
 b.pp(new IA(){

public void cc(){}//提供接口IA中的所有抽象方法的实现

});
}
}

匿名内部类的使用限制

  • 匿名内部类不能是抽象的
  • 匿名内部类不能定义构造器,默认和父类相似的构造器
  • JDK1.8-要求给局部内部类、匿名内部类访问的局部变量必须使用 nal修饰,JDK1.8开始这个现实被取消了,但是默认是 nal的(不能修改)
public void pp() {
 final Date birth = new Date();
 class C1 {
 
public void ff() {
 System.out.println(birth);
birth.setYear(2000);// 3900
 // birth=new Date(); 语法报错
 System.out.println("modify year:" + birth);

}
 }
 new C1().ff();

}

int8种简单类型/Integer8种简单类型的包装类/String的使用中应该注意

class A11 {

public void pp() {
 final Date now=new Date();
 final String str="abcde";
 int[] arr= {1,2,3,4};
 int kk=100;
 new Object() {
 @Override
 public String toString() {
 //kk++; 针对简单类型则final表示值不可变
 //针对引用类型表示地址不可变
 arr[0]=999; //arr=new int[] {3,4,5,6};对象新建了所有报错
 now.setYear(1900);//now=new Date()也会报错
 str+="ddd";//针对String类型的修改操作会引发对象的新建

return now.toGMTString();

}
}.toString();

}
}

典型的匿名内部类使用场景:

/*
* JFrame窗口。JFrame 是一个可以独立显示的组件,一个窗口通常包含有标题、图标、操作按钮(关
闭、最小化、最大化),还可以为窗口添加菜单栏、工具栏等。一个进程中可以创建多个窗口,并可在适当
时候进行显示、隐藏 或 销毁。
3
4
5
*/
public class Test1 {
public static void main(String[] args) {
6 JFrame mainWin = new JFrame("窗口标题");
7 mainWin.setSize(800, 600);
8 JPanel panel = new JPanel(); //构建panel,即一个矩形区域对象
9 JButton btn = new JButton("Show New Window");
file:///C:/Users/Administrator/Desktop/oop7.html
//创建窗口对象
//设置窗口对象的宽窄
//构建按钮
btn.addActionListener(new ActionListener() { //添加按钮对应的事件处理

public void actionPerformed(ActionEvent e) {

showNewWindow(mainWin);

}
 });
 panel.add(btn);
 mainWin.setContentPane(panel);

mainWin.setVisible(true);

}


public static void showNewWindow(JFrame relativeWindow) {
 // 创建一个新窗口
 JFrame newJFrame = new JFrame("新的窗口");
 newJFrame.setSize(250, 250);
 // 把新窗口的位置设置到 relativeWindow 窗口的中心
 newJFrame.setLocationRelativeTo(relativeWindow);
 // 点击窗口关闭按钮, 执行销毁窗口操作(如果设置为 EXIT_ON_CLOSE, 则点击新窗口关闭按钮后, 整个进程将结束)
 newJFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
 // 窗口设置为不可改变大小
 newJFrame.setResizable(false);
 JPanel panel = new JPanel(new GridLayout(1, 1));
 // 在新窗口中显示一个标签
 JLabel label = new JLabel("这是一个窗口");
 label.setFont(new Font(null, Font.PLAIN, 25));
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setVerticalAlignment(SwingConstants.CENTER);
 panel.add(label);

newJFrame.setContentPane(panel);

newJFrame.setVisible(true);

}

}

内部类的使用场景和好处

  • 每个内部类都能独立的提供一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整
  • 方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏
public class 牛{
private class 牛腿{}
}
  • 方便编写事件驱动程序
btn.addActionListener(new ActionListener() { //添加按钮对应的事件处理

public void actionPerformed(ActionEvent e) {

showNewWindow(mainWin);

}
});
  • 方便编写线程代码

标签:pp,内部,void,接口,public,static,class
来源: https://blog.csdn.net/Liuxin2448/article/details/112850278

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有