java学习——补充知识拓展

目录

一、嵌套类

1、概念

2、使用嵌套类原因

3、静态嵌套类

4、内部类

5、局部内部类

6、匿名内部类

二、Lambda表达式

1、使用原因

2、Lambda表达式标准语法

3、Lambda表达式省略规则


一、嵌套类

1、概念

Java编程语言允许你在一个类中定义一个类。 这样的类称为嵌套类。

嵌套类分为两类:静态和非静态。声明为静态的嵌套类称为静态嵌套类,非静态嵌套类称为内部类。

嵌套类是其外部类的成员。非静态嵌套类(内部类)可以访问外部类的其他成员,即使它们被产明为私有的也可以访问。静态嵌套类无权访问外部类的其他成员。作为outerClass的成员, 可以将嵌套类声明为私有,公共,受保护或包私有。回想一下,外部类只能声明为公共或包私有。

2、使用嵌套类原因

当一个事物内部还有其他事物时,使用内部类来描述就显得合理了。如计算机包括显卡、cpu、主板等事物,这些就能用内部类来描述计算机。

语法示例

 public class Computer { //计算机

    class Mainboard { //主板

    

    }

     

    class GPU{ //显卡

    

    }

    class CPU{ //CPU

    

    }

}

3、静态嵌套类

与类方法和变量一样,静态嵌套类与其外部类相关联。与静态类方法一样,静态嵌套类不能直接引用其外部类中定义的实例变量或方法:它只能通过对象引用来使用它们。

静态嵌套类与它的外部类(和其他类)的实例成员进行交互,就像其他任何顶级类一样。实际上, 静态嵌套类在行为上是顶级类,为了包装方便,该顶级类已嵌套在另一个顶级类中。

示例

使用静态内部类实现学生管理员对学生按年龄进行排序展示的功能

package Complement;

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

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package Complement;

import java.util.Arrays;

public class StudentManager { //外部类修饰只能用public或默认
    private Student[] stus={};

    public void addStudent(Student stu){
        stus=Arrays.copyOf(stus,stus.length+1);
        stus[stus.length-1]=stu;
    }

    public void showStudent(Studentsorter studentsorter){
        studentsorter.sort(stus);
        for(Student student:stus){
            System.out.println(student);
        }
    }

    static class Studentsorter{ //该静态内部类修饰符public、protected、private都行
        private int order;//排序标志:0-降序排序,1-升序排序

        public Studentsorter(){
            this(0);//无参构造,表示降序排序
        }

        public Studentsorter(int order){
            this.order=order;
        }

        public void sort(Student[] stus){
            for (int i=0;i<stus.length;i++){
                for(int j=0;j<stus.length-1-i;j++){
                    int age1=stus[j].getAge();
                    int age2=stus[j+1].getAge();
                    if((order==0&&age1<age2) || (order==1&&age1>age2)){
                        Student temp=stus[j];
                        stus[j]=stus[j+1];
                        stus[j+1]=temp;
                    }
                }
            }
        }
    }
}

package Complement;

public class StudentTest {
    public static void main(String[] args) {
        StudentManager manager=new StudentManager();
        manager.addStudent(new Student("ash",21));
        manager.addStudent(new Student("rabbit",16));
        manager.addStudent(new Student("fox",17));
        manager.addStudent(new Student("arbit",16));

        //静态嵌套类构建对象的语法:new 外部类.内部类类名()
        manager.showStudent(new StudentManager.Studentsorter(1));
        //输出:
//        Student{name='rabbit', age=16}
//        Student{name='arbit', age=16}
//        Student{name='fox', age=17}
//        Student{name='ash', age=21}
    }
}

4、内部类

与实例方法和变量一样,内部类与其所在类的实例相关联,非且可以直接访问该对象的方法和字段。另外, 由于内部类与实例相关联,因此它本身不能定义任何静态成员。

内部类对象创建语法

外部类类名.内部类类名  对象名= new 外部类类名() .new内部类类名();

示例

使用内部类描述一辆汽车拥有一台发动机

package Inner;

public class Car {

    private double price;
    private String brand;
    private Engine engine;//汽车拥有的发动机

    public Car(double price, String brand) {
        this.brand = brand;
        this.engine=new Engine("国产",20000);
        this.price = price+engine.price;
    }

    public Car(Engine engine,String brand,double price){
        this.engine=engine;
        this.brand=brand;
        this.price=price+engine.price;
    }

    public void show(){
        this.engine.show(); //输出Engine的show()方法内容
    }

    class Engine{ //发动机

        //内部类里不能定义任何静态成员

        private String type;//发动机类型
        private double price;//发动机价格

        public Engine(String type, double price) {
            this.type = type;
            this.price = price;
        }

        public void show(){
            System.out.println(brand+"汽车使用的是"+type+"发动机,价格为:"+price); //输出的是内部类的price
            //如果内部类中存在与外部类同名的成员变量时,想要使用外部类的同名成员变量,需要加上:外部类类名.this.变量名
            System.out.println("汽车总价是:"+Car.this.price); //输出外部类的price
        }
    }
}

package Inner;

public class Cartest {
    public static void main(String[] args) {
        //c是汽车类的成员,因此c对象中有Engine类成员
        Car c=new Car(100000,"奥拓");
        c.show();
        //输出:
        //奥拓汽车使用的是国产发动机,价格为:20000.0
        //汽车总价是:120000.0

        Car.Engine engine=new Car(100000,"奥拓").new Engine("进口",50000);
        engine.show();
        //输出:
        //奥拓汽车使用的是进口发动机,价格为:50000.0
        //汽车总价是:120000.0

        Car c1=new Car(engine,"奔驰",150000);
        c1.show();
        //输出:
        //奥拓汽车使用的是进口发动机,价格为:50000.0
        //汽车总价是:120000.0

        Car.Engine engine1=c.new Engine("进口",50000);
        Car c2=new Car(engine1,"奔驰",165600);
        c2.show();
        //输出:
        //奥拓汽车使用的是进口发动机,价格为:50000.0
        //汽车总价是:120000.0
    }
}

注:内部类要创建对象的话,必须要先有外部类的成员。

5、局部内部类

局部类是在一个块中定义的类,该块是一组在平衡括号之间的零个或多个语句。通常, 你会在方法的主体中找到定义的局部类。

示例

使用局部内部类描述使用计算器计算两个数的和。

package local;

public class localClass {
    public static void main(String[] args) {
        int result=calculate(4,3);
        System.out.println(result);
    }

    public static int calculate(int a,int b){
        //局部类一般使用频率很少才定义的,但不支持频繁应用
        //现在编译者都很少使用局部类,不推荐经常用
        class Calculator{
            private int num1,num2;

            public Calculator(int num1,int num2){
                this.num1=num1;
                this.num2=num2;
            }

            public int calculate(){
                return num1+num2;
            }
        }

        Calculator c=new Calculator(a,b);
        return c.calculate();
    }
}

6、匿名内部类

匿名类可以使你的代码更简洁。它们使你在声明一个类的同时实例化它。除了没有名称外,它们类似于局部类。如果只需要使用一次局部类, 则使用它们。

匿名类表达式的语法类似于构造方法的调用,不同之处在于代码块中包含类定义。

示例

package anonymous;

public interface Calculate {
    int calculate(int a,int b);
}

package anonymous;

public abstract class Animal {
    public abstract void eat();
}

package anonymous;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import org.w3c.dom.ls.LSOutput;

public class AnonymousClass {
    public static void main(String[] args){
        int result=calculate(4,750);
        System.out.println(result);

        Animal a=new Animal() {
            //使用了匿名内部类
            @Override
            public void eat() {
                System.out.println("老虎吃肉");
            }
        };
        a.eat();
    }

    public static int calculate(int a,int b){
        //匿名内部类跟构造方法的调用很相似,不同的地方在于,
        //匿名内部类里面还有类的主体
        Calculate c=new Calculate() {
            @Override
            public int calculate(int a, int b) {
                return a+b;
            }
        };
        return c.calculate(a,b);
    }
}

注:任何一个抽象类,任何一个接口,任何一个类都能调用匿名内部类。

二、Lambda表达式

1、使用原因

匿名类的一个问题是,如果匿名类的实现非常简单,比如仅包含一个方法的接口,则匿名类的语法可能看起来笨拙且不清楚。在这些情况下, 你通常试图将功能作为参数传递给另一种方法,例如,当某人单击按钮时应采取什么措施。Lambda表达式使你能够执行此操作, 将功能视为方法参数,或将代码视为数据。

示例

package lambda;

public interface Actor {

    void performance();//表演节目
}

package lambda;

public class ActorTest {
    public static void main(String[] args) {
        Actor actor=new Actor() {
            @Override
            public void performance() {
                System.out.println("演员表演节目");
            }
        };
        actor.performance(); //执行方法
    }
}

从上面的代码中可以看出:匿名内部类只是对Actor接口的实现,重点是强调其有表演节目的行为。如果能够直接将表演节目的行为赋值给actor对象的引用,使得actor对象的引用在调用接口方法时直接执行该行为,那么将大大节省代码的编写量。而Lambda表达式就能够实现这样的功能。

2、Lambda表达式标准语法

语法

( 参数类型1 变量名1, 参数类型2 变量名2, …… ,参数类型n 变量名n ) -> {

       //代码块

       [ return 返回值; ]

};

示例

package lambda;

public interface Actor {

    void performance();//表演节目
}

package lambda;

public class ActorTest {
    public static void main(String[] args) {
//        Actor actor=new Actor() {
//            @Override
//            public void performance() {
//                System.out.println("演员表演节目");
//            }
//        };
//        actor.performance(); //执行方法

        //Lambda表达式
        //下面代码属于对Actor接口的一种实现
        Actor actor=() -> {
            System.out.println("演员表演节目");
        };
        actor.performance();
    }
}

注:Lambda表达式只能使用在只有一个接口方法的接口上,只有一个接口方法的接口称之为函数式接口。

增加样例

package lambda;

public interface print {
    void showPrint(Object o);
}

package lambda;

public class objPrint {
    public static void main(String[] args) {
        //函数式编程思想
        print p=(Object o) -> {
            System.out.println(o);
        };
        p.showPrint("打印字符串");
    }
}

3、Lambda表达式省略规则

()中的所有参数类型可以省略;

如果()中有且仅有一个参数, 那么()可以省略;

如果{}中有且仅有一条语句,那么{}可以省略,这条语句后的分号也可以省略。如果这条语句是return语句,那么return关键字也可以省略。

示例

package lambda;

public interface Actor {

    void performance();//表演节目
}

package lambda;

public class ActorTest {
    public static void main(String[] args) {
//        Actor actor=new Actor() {
//            @Override
//            public void performance() {
//                System.out.println("演员表演节目");
//            }
//        };
//        actor.performance(); //执行方法

        //Lambda表达式
        //下面代码属于对Actor接口的一种实现
        Actor actor= ()-> System.out.println("演员表演节目");
        // ()中无参数,不能省去
        actor.performance();
    }
}
package lambda;

public interface print {
    void showPrint(Object o);
}

package lambda;

public class objPrint {
    public static void main(String[] args) {
        //函数式编程思想
        print p= o -> System.out.println(o);
        p.showPrint("打印字符串");
    }
}
package lambda;

public interface Calculate {
    int Calculator(int a,int b);
}

package lambda;

public class Sum {
    public static void main(String[] args) {
        Calculate c=( a, b) -> a+b;
        int result=c.Calculator(10,20);
        System.out.println(result);
    }
}

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值