目录
一、嵌套类
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);
}
}