内部类和JDK8新特性

1.内部类

类中嵌套的类,当我们需要使用一个类描述信息,并且此类没有必要被外部其他类使用,我们可以定义为内部类。

1.1普通内部类

1.在类的内部定义,与实例变量、实例方法同级别的类。(位置)

2.外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。(创建对象)

3.当外部类、内部类存在重名属性时,会优先访问内部类属性。(访问属性)

Outer.this.a访问外部类成员

4.成员内部类不能定义静态成员。(非静态不能有静态呀!!!)(规则)

Outer.Inner inner = new Outer().new Inner();

/**
 * 普通内部类
 */
public class Test1 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        System.out.println(outer.a);
        outer.m1();
        Outer.m2();
        Outer.Inner inner = new Outer().new Inner();
        inner.innerM1();
    }
}
​
class Outer{
    int a = 20;
    public void m1(){
        System.out.println("外部类普通方法m1");
    }
    
    public static void m2(){
        System.out.println("外部类静态方法m2");
    }
    
    class Inner{
        private int a = 100;
        private int b = 200;
        
        public void innerM1(){
            System.out.println(a);
            System.out.println(Outer.this.a);
            System.out.println("内部类的普通方法m1");
        }
    
        //普通内部类不能定义静态方法
    /*  public static void innerM2(){
            System.out.println("内部类的静态方法m2");
        }*/
    }
}

1.2静态内部类

1.不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。

2.只能直接访问外部类的静态成员(实例成员,即其他成员变量,属性等需实例化外部类对象)。

Outer.Inner inner = new Outer.Inner();

/**
 * 静态内部类
 */
public class Test1 {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer.Inner();
        System.out.println(inner.c);
        inner.innerM1();
        Outer.Inner.m2();//内部类的静态方法,通过类名访问
        Outer.m2();//外部类的静态方法
    }
    
}
​
class Outer{
    public int a = 20;
    public static int b = 100;
    public void m1(){
        System.out.println("外部类普通方法m1");
    }
    public static void m2(){
        System.out.println("外部类静态方法m2");
    }
    
    static class Inner{
        public int c = 30;
        public static int d = 300;
        public void innerM1(){
            //System.out.println(a);不能直接访问非静态的内容
            System.out.println(b);
            m2();
            //m1();不能直接访问非静态的内容
            System.out.println("内部类的m1方法");
        }
        public static void m2(){
            System.out.println("内部类的m2静态方法");
        }
    }
}

1.3局部内部类

1.特征与普通外部类基本相似

2.定义在外部类方法中,作用范围和创建对象范围仅限于当前方法

3.局部内部类访问外部类当前方法中的局部变量时,变量必须修饰为final,即使不写,内部类也会默认其被final修饰,即外部类局部变量只可读不可写

4.限制类的使用范围

/**
 *  局部内部类 
 */
public class Test1 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        System.out.println(outer.a);
        outer.m1();
        outer.m2();
    }
}
​
class Outer{
    int a = 20;
    public  void m1(){
        System.out.println("外部类的普通方法m1");
        int num = 100;
         class Inner{
            private int b = 2;
            public void innerM1(){
//              num++;  不能对外部类中普通方法局部变量值做改变
                System.out.println(num);
                System.out.println("局部内部类的m1");
            }
            
            //不能定义静态方法
            /*public static void m2(){
                System.out.println("局部内部类中的m2");
            }*/
        }
         Inner inner = new Inner();
         System.out.println("局部内部类中的属性b:" + inner.b);
    }
    public static void m2() {
        System.out.println("外部类的静态方法m2");
    }
}

1.4匿名内部类

1.必须实现一个接口或者继承一个抽象类

2.匿名内部类不能创建对象,只能使用一次

3.优点:减少子类的编写

4.缺点:阅读性较差

5.通常用于接口或者抽象类中只有一个抽象方法的情况

/**
 *  匿名内部类 没有名字的内部类
 */
public class Test1 {
    public static void main(String[] args) {
        Info info = new Info() {
            @Override
            public void print() {
                System.out.println("通过匿名内部类的方式实现接口");
            }
            
            @Override
            public void m2() {
                System.out.println("m1方法");
            }
            
            @Override
            public void m1() {
                System.out.println("m2方法");
            }
        };
        info.print();
        
        A a = new A(){
            @Override
            public void m1() {
                System.out.println("通过匿名内部类的方式实现抽象类");
            }
        };
        a.m1();
        
         new Thread(new Runnable() {
            
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程的内容");
            }
        },"线程A").start();;
        //t1.start();
    }
}
​
interface Info{
    void print();
    void m1();
    void m2();
}
​
abstract class A{
    public abstract void m1();
}

2.JDK8新特性

JDK8新特性

1.接口中可以使用default关键字书写普通方法

2.接口中也可以写静态方法

3.Lambda表达式解决匿名内部类代码阅读性差的问题

4.方法引用

5.stream函数式编程

2.1接口相关

JDK8中

1.接口可以使用default关键字书写普通方法(给子类使用)

2.可以书写静态方法(通过接口名+.访问)

public interface A {
    public default void m1() {
        System.out.println("普通方法,给子类使用");
    }
    
    public static void m2() {
        System.out.println("静态方法");
    }
    
    public static void main(String[] args) {
        A.m2();
    }   
}

2.2Lambda表达式

Lambda表达式属于函数式编程,可以解决匿名内部类阅读性差的问题,但是要求实现Lambda表达式必须是只有一个抽象方法的接口,但并不是只能有一个方法(default,static关键字修饰的,不是必须实现的,所以无影响)我们可以使用@FunctionalInterface注解来约束接口。https://www.cnblogs.com/haixiang/p/11029639.html

/**
 * 匿名内部类缺点:代码阅读性差
 * 可以使用JDK8提供的新特性解决这些问题
 
 *  Lambda表达式属于函数式编程的体现  一些计算机语言就是函数式的语言 比如Haskell 
 * @author asus
 */
public class Test1 {
    public static void main(String[] args) {
        A a = new A(){
            @Override
            public void print() {
                System.out.println("匿名内部类实现方式");
            }
        };
        a.print();
        
        // 使用Lambda表达式的方式实现同样的效果
        // 使用lambda表达式书写更为简洁 但是不能具体制定重写的是哪个方法
        // 所以要求接口只能有一个抽象方法,只能适用于接口
        // () - > 这个是固定书写格式 
        
        A a1 = ()->System.out.println("lambda表达式方式实现");
        a1.print();
        
        //有参数, 类型写不写无所谓
        B b = (bb)->System.out.println(bb); 
        b.print("hello word");
        
        //有返回值,return必须不写
        C c = (numa,numb)-> numa + numb;
        System.out.println(c.print("a", 20));
        
        //写多条语句
        D d =(number1,number2)->{
            String string = "hrllo";
            return string+number1+number2;
        };
        System.out.println(d.print(1, 1));
        // E e = () -> "hello world"; 抽象类不能使用lambda表达式
    }
    
}
​
interface D{
    String print(int a, int b);
}
//与@override类似,检查
@FunctionalInterface
interface A{
    void print();
    //void m1();
}
​
interface B{
    void print(String a);
}
​
interface C{
    String print(String a,int b);
}

2.3方法引用

方法引用相当于代码的重用,表示通过Lambda表达式的方式引用某个方法的方法体,可以引用构造方法,普通方法,静态方法

/**
 * 方法引用:把方法体拿来使用,方法引用也是Lambda表达式的体现
 * 构造方式引用
 * 普通方法
 * 静态方法
 */
public class Test1 {
    public static void main(String[] args) {
        //::表示方法引用
        //构造方法引用
        Info info = Book :: new;
        info.print();
        System.out.println(info.getClass().getName());
        
        Info info1 = () ->System.out.println("This is a book");
        info1.print();
        
        String flag = String.valueOf(false);
        System.out.println(flag.length());
        //静态方法引用,,引用的是静态valueof方法,不要写括号
        //通过类名String引用,与普通方法引用不同
        Message<String,Boolean> ms = String::valueOf;
        System.out.println(ms.getStr(true));
        
        String str = "abcd**";
        System.out.println(str.startsWith("a"));
        //普通方法引用,通过对象名引用
        TestStartsWith<Boolean,String> ts = str ::startsWith;
        System.out.println(ts.test("*"));
        
        System.out.println("*****************");
        PrintHello ph = System.out::println;
        ph.print("hello word");
        
        
        testHelloWord thw = String::valueOf;
        System.out.println(thw.print(123));
    }
}
​
interface testHelloWord{
    String print(int a);
}
​
@FunctionalInterface
interface PrintHello{
    void print(String str);
}
@FunctionalInterface
interface TestStartsWith<R,P>{
    R test(P p);
}
​
interface Info{
    void print();
}
​
class Book{
    public Book(){
        System.out.println("这是一本书《钢铁是怎样炼成的》");
    }
}
​
interface Message<R,P>{
    R getStr(P p);
}

2.4JDK提供的函数式接口

java.util.function这个包中全部是函数式接口

这个接口大致分为四类

功能型接口 Function 有进有出

消费型接口 Consumer 只进不出

供给型接口 Supplier 只出不进

断言型接口 Predicate

/**
 *  JDK给我们提供了一个包
 *  java.util.function 这个包中全部是函数式接口
 *  这个接口大致分为四类
 *  功能型接口  Function     有进有出
 *  消费型接口   Consumer    只进不出
 *  供给型接口   Supplier    只出不进
 *  断言型接口   Predicate
​
 */
public class Test2 {
    public static void main(String[] args) {
        //  引用String类valueOf方法
        Function<Integer, String> fun = String :: valueOf;
        System.out.println(fun.apply(23566).length());
        
        Consumer<String> con = System.out :: println;
        con.accept("hello word");
        
        String str = "abcd";
        Supplier<Integer> sup = str :: length;
        System.out.println("字符串长度" + sup.get());        
        // 利用断言接口判断字符串是否以**开头或者结尾
        Predicate<String> pre = str :: startsWith;
        System.out.println(pre.test("a"));
    }
}

 

posted on 2020-08-31 11:34  zitian246  阅读(90)  评论(0编辑  收藏  举报