# 内部类

# 基本概念

内部类是指在类内部定义的普通类,抽象类,接口的统称,在一个类的内部出了属性和方法还能定义类,这使程序的结构定义更加灵活。

class OuterClass{
    private String info="This is outer info!";
    public void GenInner() {
        InnerClass innerObj = new InnerClass();
        innerObj.GetInnerInfo();
    }
    
    class InnerClass{
        public void GetInnerInfo() {
            System.out.println(OuterClass.this.info);
        }
    }
}

public class Main {
    public static void main(String[] args){
        OuterClass outObj = new OuterClass();
        outObj.GenInner();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

注意:

  • 内部类能比较方便地访问外部类的私有成员,外部类也能比较方便地访问内部类的私有成员。
  • 内部类可以被单独地实例化,但是需要先实例化外部类。如果不希望在外部实例化内部类,需要在内部类前使用private修饰。

# 接口内部类

内部类可以在接口里面定义:

interface IOuterInterface{
    public void getOuterInfo();
    interface IInnerInfo{
        public void getInnerInfo();
    }
}

class OuterImpl implements IOuterInterface{

    @Override
    public void getOuterInfo() {
        // TODO Auto-generated method stub
        System.out.println("Output outer class info!");
        InnerImpl innerObj = new InnerImpl();
        innerObj.getInnerInfo();
    }

    class InnerImpl implements IInnerInfo{

        @Override
        public void getInnerInfo() {
            // TODO Auto-generated method stub
            System.out.println("Output inner class info!");
        }
    }
}

public class Main {
    public static void main(String[] args){
        OuterImpl o1 = new OuterImpl();
        o1.getOuterInfo();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

在接口中定义抽象类:

interface IOuterInterface{
    public void getOuterInfo();

    abstract class InnerAbstractClass{
        public abstract void GetInnerInfo();
    }

}

class OuterImpl implements IOuterInterface{

    @Override
    public void getOuterInfo() {
        // TODO Auto-generated method stub
        System.out.println("Output outer class info!");
        innerClass innerClassObj = new innerClass();
        innerClassObj.GetInnerInfo();
    }

    class innerClass extends InnerAbstractClass{

        @Override
        public void GetInnerInfo() {
            // TODO Auto-generated method stub
            System.out.println("abstract class info!");
        }
    }
}

public class Main {
    public static void main(String[] args){
        OuterImpl o1 = new OuterImpl();
        o1.getOuterInfo();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

接口子类定义实现自身接口的类,在JDK1.8以后在接口中可定义static方法,可利用内部类的概念直接在接口中进行该接口子类的定义。

interface IOuterInterface{
    public void getOuterInfo();
    class OuterClass implements IOuterInterface{
        @Override
        public void getOuterInfo() {
            // TODO Auto-generated method stub
            System.out.print("Outer class implements IOuterInterface!");
        }
    }
    public static IOuterInterface getInstance(){
        return new OuterClass();
    }
}

public class Main {
    public static void main(String[] args){
        IOuterInterface outerInterface = IOuterInterface.getInstance();
        outerInterface.getOuterInfo();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 内部静态类

使用static定义内部类时,此时的内部类不再受外部类实例化对象的影响,等同于是一个外部类。

interface MyInterface{
    static interface Common {
        void getInfo(String targetStr);
    }
}

class MyInterfaceImpl implements MyInterface.Common{

    @Override
    public void getInfo(String targetStr) {
        // TODO Auto-generated method stub
        System.out.println("Common interface:"+targetStr);
    }

}

class OuterClass{
    private static final String info ="outer class info!";

    static class Inner{
        public void printInfo(MyInterface.Common interface1) {
            interface1.getInfo(info);
        }
    }
}



public class Main {
    public static void main(String[] args){
        OuterClass.Inner o1 = new OuterClass.Inner();
        MyInterfaceImpl m1= new MyInterfaceImpl();
        o1.printInfo(m1);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 方法中的内部类

内部类可在任何代码块或方法中定义,在JDK1.8之前,内部类要访问方法的参数,需要添加final关键字,就像testScope2一样。

public class Main {
    public static void main(String[] args){
        testScope("hello world!");
        testScope2("hi world!");


    }
    public static void testScope(String str) {
        class Inner{
            public void PrintInner() {
                System.out.println(str);
            }
        }
        Inner innerObj1 = new Inner();

        innerObj1.PrintInner();
    }

    public static void testScope2(final String str) {
        class Inner{
            public void PrintInner() {
                System.out.println(str);
            }
        }
        Inner innerObj1 = new Inner();

        innerObj1.PrintInner();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 匿名内部类

在一个接口或抽象类完成后,当我们需要一个子类时我会先定义一个子类然后使用,如果这个子类可能只用一次,为它单独创建一个类文件很不合理,这个时候就用匿名类了:

interface ITempInterface{
    public void send(String str);
}

class TempClass{
    public void Send(String str) {
        System.out.println("this is org string:"+str);
    }
}

public class Main {
    public static void main(String[] args){
        ITempInterface t1 = new ITempInterface() {

            @Override
            public void send(String str) {
                // TODO Auto-generated method stub
                System.out.println(str);
            }
        };
        t1.send("hello world!");

        TempClass tempClassObj1 = new TempClass() {
            @Override
            public void Send(String str) {
                System.out.println("this is new string:"+str);
            }
        };

        tempClassObj1.Send("xie");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

在接口中可使用匿名类来实现接口:

interface InfoMessage{
    public void send(String str);
    public static InfoMessage getInstance() {
        return new InfoMessage() {

            @Override
            public void send(String str) {
                // TODO Auto-generated method stub
                System.out.println("infoMessage:"+str);
            }
        };
    }
}

public class Main {
    public static void main(String[] args){
        InfoMessage infomessage1 = InfoMessage.getInstance();
        infomessage1.send("useful info!");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Lambda表达式

Lambda表达式是从JDK1.8中引入的,是指应用在SAM(Simple Abstract Method,含有一个抽象方法的接口)下的一种简化形式,用来解决匿名内部类定义的问题。

interface InfoMessage{
    public void send(String str);
}

@FunctionalInterface
interface MyMath{
    public int Add(int a,int b);
}

public class Main {
    public static void main(String[] args){
        InfoMessage infomessage1 = (str)->{
            System.out.println("Lambda 方法:"+str);
        };
        infomessage1.send("useful info!");
        MyMath mathOper = (a1,a2)->a1+a2;
        System.out.println("a1+a2:"+mathOper.Add(1,20));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 方法引用

在Java中利用对象的引用可以用不同的变量来引用相同的内存空间,从JDK1.8开始,方法也支持引用操作,相当于为方法定义了别名。方法的引用有四种形式:

  • 引用静态方法: 类名::方法名
  • 引用对象方法: 类名::普通方法
  • 引用特定类型的方法: 特定类::普通方法
  • 引用构造方法: 类名::new
@FunctionalInterface
interface IFuncFromStatic<P,R>{
    public R change(P p);
}

@FunctionalInterface
interface IFuncFromCommon<R>{
    public R MyUpper();
}

@FunctionalInterface
interface IFuncFromClassCommon<P>{
    public int compare(P p1,P p2);
}


public class Main {
    public static void main(String[] args){
        IFuncFromStatic<Integer,String> staticRef = String::valueOf;
        String str = staticRef.change(1000);
        System.out.println(str.length());

        IFuncFromCommon<String> commonRef = "hello world!"::toUpperCase;
        System.out.println(commonRef.MyUpper());

        IFuncFromClassCommon<String> commonClassCompare = String::compareTo;
        System.out.println(commonClassCompare.compare("hello", "hi"));

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

下面是调用构造函数:

class MyClass{
    public MyClass() {
        // TODO Auto-generated constructor stub
        System.out.println("this is myclass constructor!");
    }
}

@FunctionalInterface
interface IFuncFromNew<R>{
    public R NewMyClass();
}


public class Main {
    public static void main(String[] args){
        IFuncFromNew<MyClass> createClass = MyClass::new;
        createClass.NewMyClass();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 内建函数式接口

函数式接口是实现Lambda表达式的关键,在上面方法的引用中发现,不管如何操作,函数式接口最多有四种:

  • 有参数有返回值
  • 有参数无返回值
  • 无参数有返回值
  • 判断真假

为了简化开发者定义,从JDK1.8之后提供了新包:java.util.function,此包中提供了很多内置的函数式接口,以上面四个核心接口为例,它们的原型为:

//功能型函数式接口
@FunctionalInterface
public interface Function<T,R>{
    public R apply(T t);
}
//消费型函数式接口
@FunctionalInterface
public interface Consumer<T>{
    public void accept(T t);
}
//供给型函数式接口
@FunctionalInterface
public interface Supplier<T>{
    public T get();
}
//断言型函数式接口
@FunctionalInterface
public interface Predicate<T>{
    public boolean(T t);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

它们的实例为:

import java.util.function.*;

public class Main {
    public static void main(String[] args){

        //功能型函数式接口
        Function<String, Boolean> beginWith = "*Hello world!"::startsWith;
        System.out.println(beginWith.apply("*"));

        //消费型函数式接口
        Consumer<String> MyPrint = System.out::println;
        MyPrint.accept("hello");

        //供给型函数式接口
        Supplier<String> changeToUpper = "hello world"::toUpperCase;
        System.out.println(changeToUpper.get());

        //断言型函数式接口
        Predicate<String> pre = "hello world"::endsWith;
        System.out.println(pre.test("rld"));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22