目录
一、内部类
1、定义在类中定义的另一个类或是在类的方法中定义的另外一个类
创建对象的格式:
class Outer{
class Inner{
}
}
外部类.内部类 内部类对象名 = new 外部类对象().new内部类对象()
Outer.Inner in = new Outer().new Inner();
二、内部类的分类
一般有四种类:成员内部类、局部内部类、匿名内部类和静态内部类
1、成员内部类
成员访问特点
(1)内部类中,访问外部类成员:直接访问,包括私有
下面是代码示例:
/**
* @author Tweek
*/
public class NestedClasses {
public static void main(String[] args) {
Outer.Inner in = new Outer().new Inner();
in.show();
}
}
class Outer{
/**
* 内部类访问外部类成员
*/
private int num = 30;
public void method(){
System.out.println("I'm a method of Outttter!");
}
class Inner{
public void show(){
System.out.println(num); //直接访问外部类的私有成员变量
method(); //直接访问外部类的成员方法
}
}
}
控制台输出:
30
I'm a method of Outttter!
(2)外部类中,访问内部类成员:需要创建对象访问
下面是代码示例:
/**
* @author Tweek
*/
public class NestedClasses {
public static void main(String[] args) {
Outer.Inner in = new Outer().new Inner();
in.show();
Outer outer = new Outer();
outer.method();
}
}
class Outer{
/**
* 外部类访问内部类的访问特点
*/
Inner inner = new Inner(); //创建内部类的对象
public void method(){
inner.show();
}
class Inner{
public void show(){
System.out.println("I'm a method of Innnnnnner!");
}
}
}
控制台输出:
I'm a method of Innnnnnner!
I'm a method of Innnnnnner!
(3)内部类与外部类变量重名时的访问特点
下面是代码示例:
/**
* @author Tweek
*/
public class NestedClasses {
public static void main(String[] args) {
Outer.Inner in = new Outer().new Inner();
in.show();
}
}
class Outer{
/**
* 变量访问特点
*/
int num =10;
class Inner{
int num =20;
public void show(){
int num =30;
System.out.println(num); //就近原则访问变量
System.out.println(this.num); //在该内中的成员变量
System.out.println(Outer.this.num); //类名引用成员变量
}
}
}
2、静态内部类
静态内部类:static修饰的成员内部类
(1)创建对象格式
class Outer{
static class Inner{
}
}
外部类名.内部类名 对象名 = new 外部类名.内部类对象();
Outer.Inner in = new Outer.Inner();
(2)调用方法
一般情况:
下面是代码示例:
/**
* @author Tweek
*/
public class NestedClasses {
public static void main(String[] args) {
Outer.Inner in = new Outer.Inner();
in.show();
}
}
class Outer{
/**
* 访问static内部类中的方法
*/
static class Inner{
public void show(){
System.out.println("I'm a method of Innnnnnner!");
}
}
}
控制台输出:
I'm a method of Innnnnnner!
当内部类方法被static修饰时:
/**
* @author Tweek
*/
public class NestedClasses {
public static void main(String[] args) {
Outer.Inner.show(); //因为内部类中的方法是静态的,且内部类也是静态的,故调用静态类中的静态方法时可以用类名调用
}
}
class Outer{
/**
* 访问static内部类中static修饰的方法
*/
static class Inner{
public static void show(){
System.out.println("I'm a method of Innnnnnner!");
}
}
}
控制台输出:
I'm a method of Innnnnnner!
注意:静态内部类只能调用静态方法,当静态内部类想要调用外部类的非静态成员时,需要在内部类中创建对象。
下面是代码示例:
/**
* @author Tweek
*/
public class NestedClasses {
public static void main(String[] args) {
Outer.Inner.show(); //因为内部类中的方法是静态的,且内部类也是静态的,故调用静态类中的静态方法时可以用类名调用
}
}
class Outer{
/**
* static内部类访问外部类的成员
*/
int num =20;
public void method(){
System.out.println("I'm a method of Outtttter!");
}
static class Inner{
public static void show(){
Outer outer = new Outer(); //创建外部类的对象
outer.method();
System.out.println(outer.num);
System.out.println("I'm a method of Innnnnnner!");
}
}
}
控制台输出:
I'm a method of Outtttter!
20
I'm a method of Innnnnnner!
3、局部内部类
局部内部类:存在与方法、底阿妈快、构造器等执行体中
下面是代码示例:
/**
* @author Tweek
*/
public class Test2 {
public static void main(String[] args) {
Outer outer = new Outer(); //创建外部类对象
outer.method(); //调用外部类方法,外部类方法进入内部类,找到外部类中创建的局部内部类对象,再用局部类对象调用其方法show()
}
}
class Outer{
/**
* 局部内部类
* 例在方法内定义
*/
public void method(){
class Inner{
public void show(){
System.out.println("I'm a method of Innnnner!");
}
}
Inner inner = new Inner(); //外部类访问内部类,先创建局部内部类对象
inner.show(); //调用内部类方法
}
}
控制台输出:
I'm a method of Innnnner!
4、匿名内部类
匿名内部类:匿名内部类是一种特殊的内部类,定义在方法内部。
定义匿名内部类的前提:需要存在一个接口或类
格式:new 类名\接口名(){
}
new 类名(){} : 代表继承这个类
new 接口名(){}: 代表实现这个接口
匿名内部类的使用场景:若接口中的方法只有一个时(方法多的时候不建议使用匿名内部类,这样会使得代码变得臃肿,适得其反),我们可以使用匿名内部类,来使得我们的代码更加地简洁,因为若不使用匿名内部类,我们则需要创建新的类并实现接口,调用新类中重写接口的方法。
下面的代码示例,能让我们更好地理解匿名内部类
/**
* @author Tweek
*/
public class NCTest3 {
public static void main(String[] args) {
/**
* 通过额外的类来实现接口
* 当方法参参数为接口时,我们此时应该传入接口的实现类,因为接口不能实例化。
*/
userInter(new InterImp());
userInter(new Inter(){
/**
* 通过匿名内部类来实现接口中的方法,不用再额外创建一个类来实现接口
*/
@Override
public void show() {
System.out.println("I'm a method of The Interface Inter!");
}
} );
}
/**
* 此处方法的参数传入的是一个接口,但是接口不能实例化,所以有两种方法
* 1、创建新类实现接口
* 2、利用方法内部的匿名内部类来实现接口中的方法
* @param i
*/
public static void userInter(Inter i){
i.show();
}
}
interface Inter{
void show();
}
class InterImp implements Inter{
@Override
public void show() {
System.out.println("I'm a method of The InterImp!");
}
}
控制台输出:
I'm a method of The InterImp!
I'm a method of The Interface Inter!
三、Lambda表达式
1、Lambda表达式
JDK8开始后的一种新语法形式
作用:简化你们内部类的代码写法
格式:() -> {}
() : 匿名内部类被重写方法的形参列表
{} : 被重写方法的方法体代码
注意:Lambda表达式,只允许操作函数式变成接口:即有且仅有一个抽象方法的接口!
下面的代码示例,能让我们更好地了解Lambda表达式
/**
* @author Tweek
*/
public class NCTest3 {
public static void main(String[] args) {
/**
* 利用Lambda表达式来简化匿名内部类
* Lambda表达式格式: () -> {}
*
*/
userInter(()->{ System.out.println("I'm a method of The Interface Inter!");});
}
public static void userInter(Inter i){
i.show();
}
}
interface Inter{
void show();
}
控制台输出:
I'm a method of The Interface Inter!
2、Lambda表达式的省略写法
(1)参数类型可以省略不写
下面是代码示例:
/**
* @author Tweek
*/
public class NCTest3 {
public static void main(String[] args) {
/**
* 省略参数类型
*/
userCalculator(new Inter() {
@Override
public int calculate(int a, int b) {
return a + b;
}
});
System.out.println("---------------------------------");
//省略参数类型
userCalculator((a,b)->a+b);
}
public static void userCalculator(Inter i){
int result= i.calculate(10,20);
System.out.println(result);
}
}
interface Inter{
int calculate(int a,int b);
}
控制台输出:
30
---------------------------------
30
(2)如果只有一个参数,参数类型可以省略,同时()也可以省略。
下面是代码示例:
/**
* @author Tweek
*/
public class NCTest3 {
public static void main(String[] args) {
/**
* 如果只有一个参数,参数类型可以省略,同时() 也可以省略
*
*/
userInter(s->{ System.out.println("I'm a method of The Interface Inter!"+s);});
}
public static void userInter(Inter i){
String s = "GOOD";
i.show(s);
}
}
interface Inter{
void show(String s);
}
控制台输出:
I'm a method of The Interface Inter!GOOD
(3)如果Lambda表达式的方法体代码只有一行代码时
1.可以省略大括号不写,同时要省略分号
下面是代码示例:
/**
* @author Tweek
*/
public class NCTest3 {
public static void main(String[] args) {
/**
可以省略代码的大括号,同时省略分号
*/
userInter(s-> System.out.println("I'm a method of The Interface Inter!"+s));
}
public static void userInter(Inter i){
String s = "GOOD";
i.show(s);
}
}
interface Inter{
void show(String s);
}
控制台输出:
I'm a method of The Interface Inter!GOOD
2.此时,如果这行代码是return语句,必须省略return,同时也必须省略一个;
/**
* @author Tweek
*/
public class NCTest3 {
public static void main(String[] args) {
/**
* 如果一行代码是return语句,那么必须省略return与;
*/
userRandom(new Inter() {
@Override
public int getNumber() {
return new Random().nextInt(100)+1;
}
});
System.out.println("---------------------------------");
userRandom(()->new Random().nextInt(100)+1);
}
public static void userRandom(Inter i){
int result= i.getNumber();
System.out.println(result);
}
}
interface Inter{
int getNumber();
}
控制台输出:
41
---------------------------------
93
3、Lambda表达式和匿名内部类的区别
(1)使用限制不同
1.匿名内部类:可以操作类,接口
2.Lambda表达式:只能操作函数式接口
(2)实现原理不同
1.匿名内部类:编译之后,产生一个单独的.class字节码文件
2.Lambda表达式:编译之后,没有一个单独的.class字节码文件