内部类

                                        内部类

内部类的作用:

     内部类是即在一个类的内部定义另一个类,内部类就成为外部类中的成员,访问权限遵循类成员的访问权限机制,可以是public、protected、缺省和private,

     每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响

    内部类可以定义为接口,并且可以定义另外一个类来实现它

    内部类可以定义为抽象类,可以定义另外一个内部类继承它

 

内部类的分类:

  • 内部类定义在成员位置上:成员内部类
  • 内部类定义在局部位置上:局部内部类
  • 没有名字的内部类:   匿名内部类
  • 被static修饰的内部类:静态内部类
//成员内部类
//外部类
public class OuterClass {
    private String name;
    private int age;

    // 成员内部类可以直接使用外部类的成员变量
    public class InnerClass {
        // 内部类的构造方法
        public InnerClass() {
            name = "jack"; // 外部类的成员变量赋值
            age = 12;// 外部类的成员变量赋值
        }

        // 内部类的方法
        public void display() {
            System.out.println("name=" + name + "  age=" + age);
        }
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass(); // 1.外部类的对象
        OuterClass.InnerClass inner = null;// 2.以外部类.内部类的形式进行声明
        inner = outer.new InnerClass(); // 3.以外部类对象.new 内部类构造方法()的方式构建对象
        inner.display(); // 调用内部类的方法
    }

}
  • 内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)

  • 对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class

  • 成员内部类中不能存在任何static的变量和方法内部类的实例化是由外部类实例化之后才加载的,如果外部类还没有实例化,这时候调用内部类的静态成员,此时内部类还没有被加载,却要开始创建静态成员,显示是不合理的,

    所以内部类中不能使用静态方法

  • 成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类

//局部内部类
//外部类
public class OuterClass1 {
    private String name;  //成员变量
    private int age;//成员变量
    //外部类的成员方法   
    public void display(int age1) {
        //局部内部类写在局部--方法里
         class InnerClass{
            //内部类的构造方法
            public InnerClass() {
                name = "jack";
                age = age1;  //可以调用外部类的成员变量,也可以调用成员方法的局部变量(方法的参数,常量等)
            }
             //内部类的显示方法
            public void display() {
                System.out.println("name="+name+"  age="+age);
            }
        }
        InnerClass inner = new InnerClass();//创建内部类对象
        inner.display();  //调用内部类中的display方法
    }
    
    public static void main(String[] args) {
        OuterClass1 outer = new OuterClass1();   //创建外部类对象
        outer.display(13); //调用外部类的成员方法
    }
}

  静态内部类:

     非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外部类,但是静态内部类却没有。没有这个引用就意味着:

  • 它的创建是不需要依赖于外部类

  • 不能使用任何外部类的非static成员变量和方法

  • 和成员内部类不同,static内部类能够声明static的成员

//外部类
public class OuterClass2 {
    //静态成员变量
    private static String name ="jim"; //外部类静态成员变量,所以new 对象共享静态成员变量,外部类名.静态成员变量
    //成员变量
    private int age;

    //定义静态内部类
    static class InnerClass{
        //静态内部类成员变量
        static String innerStaticName ="jack";//静态内部类的 静态成员变量
        int innerAge;
        static void InnerStaticDisplay(){
            //静态方法能够调用静态成员变量
            System.out.println("静态内部类的静态方法InnerStaticDisplay被触发,innerStaticName="+innerStaticName);
        }

        void innerDisplay(){
            //非静态方法可以调用静态和非静态成员变量
            System.out.println("静态内部类的非静态方法innerDisplay被触发,innerStaticName="+innerStaticName+",innerAge"+innerAge);
        }
    }

    //外部类的成员方法
    void outerDisplay(){
        //外部类的方法可以调用静态内部类的静态成员变量
        System.out.println(InnerClass.innerStaticName);
        //外部类的方法可以调用静态内部类的静态成员方法
        InnerClass.InnerStaticDisplay();
    }

    public static void main(String[] args) {
        OuterClass2 outer =new OuterClass2();
        outer.outerDisplay();
        //创建静态内部类对象 直接new静态内部类构造方法,不依赖outer对象
        OuterClass2.InnerClass innerClass =new OuterClass2.InnerClass();
        innerClass.innerDisplay();
        //调用静态内部类的静态方法
        OuterClass2.InnerClass.InnerStaticDisplay();
    }
}

内部类中的this及类名.this的使用:

  • 由于内部类本质上是一个独立的类,因此在内部类中直接使用this,其指代的是内部类自身的引用,如果要想引用外部内的对象,则应该使用外部类类名.this的方式

//外部类
public class OuterClass3 {
    private int i=10; //外部类的成员变量

    //成员内部类
    public class InnerClass {
        private int i=100;//内部类的成员变量

        void display(){
            System.out.println(this.i);//内部类的成员变量 ,this指定是内部类的对象范围
            System.out.println(OuterClass3.this.i);//外部类的成员变量i 外部类名.this 外部的对象引用
        }
    }
    public static void main(String[] args) {
        //1.创建外部类对象
        OuterClass3 outer =new OuterClass3();
        //2.创建内部类对象
        OuterClass3.InnerClass inner =outer.new InnerClass();
        //3.调用内部类对象的display方法
        inner.display();
    }
}

匿名内部类:

  • 如果一类内部类仅需要构建一个单一的对象,那么这个类其实并不需要额外取一个特有的名字,对于不存在名字的内部类,我们称为匿名内部类

  • 匿名内部类必须继承一个父类或实现一个接口

public interface Foo {
    void display();
}


public class OuterClass4 {
    private String name;
    private  int age;

    //创建 实现Foo接口对象,赋值给foo成员变量
    Foo foo=new Foo() {
        @Override
        public void display() {
            System.out.println("实现Foo接口匿名类,display方法被调用");
        }
    };
    //创建继承OuterClass2匿名类的对象 赋值给outerClass2 成员变量
    OuterClass2 outerClass2 =new OuterClass2(){
      public void outerDisplay(){
            System.out.println("重写OuterClass2.outerDisplay方法");
        }
    };

    public static void main(String[] args) {
        OuterClass4 outer =new OuterClass4();
        outer.foo.display();
        outer.outerClass2.outerDisplay();
    }
}
  • 匿名内部类没有构造方法(匿名内部类没有显式类名)

  • 匿名内部类要想完成一些初始化工作可以交由类初始化或实例初始化代码块来完成

  • 匿名内部类对类成员、方法临时变量的访问规则和具备名字的内部类保持一致

Lambda表达式:

  • Lambda表达式主要是替换了原有匿名内部类的写法,也就是简化了匿名内部类的写 法

  • lambda语法结构:

    lambda表达式的基本组成由 参数列表、->、方法体(单句时可不加大括号) 三部 分组成

    (参数类型 参数名称) -> {

    业务代码块}

lambda表达式的重要特征: 

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。

 1. 不需要参数,返回值为 5 :() -> 5

interface A{
    int ma();
}
public class LambdaTest {
    public static void main(String[] args) {
           test01();
    }
    
    static void test01(){
         /*A a =new A() {
            @Override
            public int ma() {
                return 5;
            }
        };*/
        A a=()->5;
        System.out.println(a.ma());
    }
} 

2.接收一个参数(数字类型),返回其2倍的值: x -> 2 * x

interface B{
    int ma(int x);
}

public class LambdaTest {
    
   ......
    static void test02(){
        /*B a=new B() {
            @Override
            public int ma(int x) {
                return 2*x;
            }
        };*/
        B b=x->2*x;
        System.out.println(b.ma(10));
    }
   ......
}

3.接受2个参数(数字),并返回他们的差值: (x, y) -> x – y

interface C{
    int ma(int x,int y); 
}

public class LambdaTest {
    
   ......
    static void test03(){
        /* C a=new C() {
            @Override
            public int ma(int x, int y) {
                return x-y;
            }
        };*/
           C c=(x,y)->x-y;
        System.out.println(c.ma(20,10));
    }
   ......
}

3.接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void): (String s) -> System.out.print(s)

interface D{
    void ma(String s); 
}

public class LambdaTest {
    
   ......
    static void test03(){
        /* D a=new D() {
           @Override
           public void ma(String s) {
               System.out.println(s);
           }
       };*/
       D d=s-> System.out.println(s);
       d.ma("Hello World");
    }
   ......
}

4.用于替代匿名内部类的Lambda表达式例子

interface E{
    void display();
}

public class AnonymousInnerClass {
    private String name="Jerry";
    private int age=24;
    /*E e=new E() {
        @Override
        public void display() {
            System.out.println("name = " + name+",age = " + age);
        }
    };*/
    E e=()-> System.out.println("name = " + name+",age = " + age);

    public static void main(String[] args) {
        AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass();
        anonymousInnerClass.e.display();
    }
}

Lambda表达式对返回的实例类型的要求

可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定 达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解,编译器如果 发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的

@FunctionalInterface
interface D{
    void ma(String s); 
    default  public  void foo(){//可以存在默认方法
        System.out.println("默认方法");
    }
    //void foo1();//需要实现的抽象方法不止一个,编译器报错
}

public class LambdaTest {
    
   ......
    static void test03(){
        /* D a=new D() {
           @Override
           public void ma(String s) {
               System.out.println(s);
           }
       };*/
       D d=s-> System.out.println(s);
       d.ma("Hello World");
    }
   ......
}

重要实例:匿名内部类和Lambda表达式

 


public interface TestService {
int mm=20; //相当于 public static final mm=20;
default void ma(){
System.out.println("TestService接口的ma方法");
}

void test();
}

public
class Test { int a=10; public void test1() { //定义局部变量 int c=10; final int d =20; TestService service1 = new TestService() { @Override public void test() { System.out.println(a); a=a+2;//匿名类对象方法是可以修改和使用成员变量 System.out.println(c);//能使用局部变量(隐含的final) //c=c+2; //修改c变量值就报错,说明final System.out.println(d);//能够使用final的局部变量 //d=d+30;//不能修改final变量 System.out.println("匿名内部类对象实现test方法"); ma();//匿名内部类方法体内可以调用接口defalut方法(默认方法) System.out.println(TestService.mm); //匿名内部类的方法体内部定义变量,是可修改的 int ff =0; ff =ff+2; } }; service1.test(); System.out.println("====================="); int b = 12; //标准写法 TestService service2 = () -> { System.out.println(a); //lambda可以修改和使用成员变量 a=a+2; System.out.println(b); //能使的局部变量(隐含final) //b =b+2; //修改就报错,就说明b是隐含的final System.out.println("标准写法lambda实现的test方法"); //ma(); //lambda方法体内不能调用接口defalut方法(默认方法) System.out.println(TestService.mm); //lambda的方法体内部定义变量,是可修改的 int ff =0; ff =ff+2; }; } }

::操作符

::操作符主要用作静态方法、成员方法或构造方法的绑定

 

 1.::绑定静态方法

public class Test1 {
    public static void main(String[] args) {
        // 把Integer的静态方法 valueOf 绑定给IntegerFactory的cInteger方法
        // 调用factory.cInteger()相当于调用Integer.valueOf方法
        IntegerFactory factory =Integer::valueOf;
        Integer integer =factory.cInteger("254");
        System.out.println(integer);

    }
}

2.绑定实例成员方法

public class Test2 {
    //定义成员方法
    public void foo(){
        System.out.println("Test2的foo方法");
    }

    public static void main(String[] args) {
        //创建Test2对象
        Test2 t=new Test2();
        //把test2对象的foo方法绑定Foo接口的ifoo方法上,要求返回值和参数列表一致
        Foo foo =t::foo;
        //调用foo.ifoo()方法
        foo.ifoo();
    }
}

3.绑定构造方法

@FunctionalInterface
public interface PersonFactory {
    Person create(String firstName,String lastName);

public class Person {
    String firstName;
    String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Person() {
    }

    public Person(String firstName) {
        this.firstName = firstName;
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                '}';
    }

    public static void main(String[] args) {
        PersonFactory pf =Person::new;//把Person的构造方法绑定PersonFactory接口匿名类create方法上
        Person p=pf.create("张","三");
        System.out.println(p);
    }
}

 

posted @ 2022-03-19 16:01  任任不买鞋子  阅读(91)  评论(0)    收藏  举报