【Java之旅】12. 深浅拷贝、内部类、lambda表达式

【Java之旅】12. 深浅拷贝、内部类、lambda表达式

12. 1 深浅拷贝

① 浅拷贝

​ 我们先看代码

public class Client {
    public static void main(String[] args) {
        Players p1 = new Players(1,"kupurk");
        Players p2 = p1;
        System.out.println("p1 = " + p1);
        System.out.println("p2 = " + p2);
    }
}

输出结果

p1 = Players{id=1, name='kupurk'}
p2 = Players{id=1, name='kupurk'}

我们构造了一个对象,用p1引用指向这个对象,我们再给p2赋于这个对象的地址,这便是浅拷贝,

但又由于两个引用指向的是同一个对象的原因,所以我们不好对 对象 进行修改。


② 深拷贝

如果我们想要两个对象,将其中一个对象的所有属性复制到另一个对象上,

这样就好对 对象 进行修改了,因此就有了深拷贝

深拷贝可以有两种方法

(1) clone()

③ 总结

  • 浅拷贝:
  • 深拷贝

12. 2 内部类

内部类顾名思义,是一个类内部中的类,如:

public class OuterClass
{
    class InnerClass
    {
        ;
    }
}

这种在一个类中定义另一个类的形式便是内部类,内部类分四种:成员内部类、静态内部类、局部内部类、匿名内部类

① 成员内部类

主类:

package study.InnerClass;

public class Client2 {
    public static void main(String[] args) {
        OuterClass.InnerClass in1 = new OuterClass().new InnerClass();
        in1.say();
        OuterClass out = new OuterClass();
        OuterClass.InnerClass in2 = out.new InnerClass();
        in2.say();
    }
}

内部类与外部类:

package study.InnerClass;

public class OuterClass
{
    class InnerClass
    {
        public InnerClass()
        {
            System.out.println("内部类构造!");
        }
        void say()
        {
            System.out.println("内部类重写调用say!!");
        }
    }
}

输出结果:

内部类构造!
内部类重写调用say!!
内部类构造!
内部类重写调用say!!

我们可以发现有两种方式可以定义构造内部类

1、	OuterClass.InnerClass in1 = new OuterClass().new InnerClass();

2、	OuterClass out = new OuterClass();
     OuterClass.InnerClass in2 = out.new InnerClass();

这两种方法都可以构造内部类,前提都是先对外部类进行构造以后,才可对内部类进行构造。


②静态内部类

静态内部类和成员内部类类似,也是一个类中的属性,只不过是静态的属性。

而静态内部类也有许多条件

  • 非静态内部类不能拥有静态成员,静态内部类可以拥有静态成员和非静态成员
package study.InnerClass;

public class OuterClass
{
    class InnerClass1
    {
        static int a;
        int b;
        static void m1()
        {}
        void m2()
        {}
    }
    static class InnerClass2
    {
        int a;
        static int b;
        static void m1()
        {}
        void m2()
        {}
    }
}

编译报错,这个普通的内部类的变量不能有静态修饰

而下面的静态内部类InnerClass2没有报错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CtOezdGG-1614924239947)(C:\Users\37484\AppData\Roaming\Typora\typora-user-images\image-20210206024819293.png)]


  • 静态内部类的静态成员可以访问外部类的静态变量,不能访问外部类的非静态成员

  • 静态内部类的非静态成员可以访问外部类的静态变量和非静态成员

  • 外部类访问非静态内部类的成员

③ 局部内部类

在类中的方法中定义类,并且构造这个类,这个内部类变为局部内部类

局部内部类的声明周期很短,出了那个外部类,就结束了。

package study.InnerClass;

public class Client2 {
    public static void main(String[] args) {
        OuterClass kupurk = new OuterClass();
        kupurk.run();
    }
}
public class OuterClass
{
    int a;
        public void run()
        {
            class InnerClass{
                void fun()
                {
                    System.out.println("局部内部类启动");
                }
            }
            InnerClass p1 = new InnerClass();
            p1.fun();
        }
}

从代码中我们可以看到,我们是在方法中定义的一个内部类,这便是局部内部类。

他的生命周期只存在于那个方法的范围内。

但正应如此,我们不必要对方法中的局部内部类去命名,于是便诞生了匿名内部类

④ 匿名内部类

匿名内部类可以使你的代码更加简洁,我们可以在定义一个类的同时对其进行实例化。

它与局部类很相似,不同的是它没有类名,如果某个局部类只需要用一次,那么我们就可以使用匿名内部类.

以刚刚的局部内部类为例,用匿名内部类写一个与他等价的代码

第一种调用方法:将匿名内部类写在代码块中
package study.InnerClass;
public class Client2 {
    public static void main(String[] args) {
        OuterClass kupurk = new OuterClass();
        kupurk.run();
    }
}

public interface IRun {
    void fun();
}

public class OuterClass {
    public void run()
    {
        new IRun(){
            public void fun(){
                System.out.println("内部类启动");
            }
        }.fun();
    }
}

主要 看最后一段代码

我们在run方法中 new了一个对象,这个对象所对应的类是没有名字的,因此叫匿名内部类

new [接口名或父类名](){
		重写实现方法
		...    
}.调用方法名();
第二种调用方法:将匿名内部类写在方法参数中
package study.InnerClass;

public class Client2 {
    public static void main(String[] args) {
        OuterClass kupurk = new OuterClass();
        kupurk.run(new IRun() {
            @Override
            public void fun() {
                System.out.println("匿名内部类参数调用");
            }
        });
    }
}


public interface IRun {
    void fun();
}
public class OuterClass {
    int a;
    public void run(IRun canshu)
    {
        canshu.fun();
    }
}

主要看main方法中的调用,我们在参数列表中定义声明了一个内部类

lambda表达式

上述调用匿名内部类的方法可能过于复杂,使用的时候会比较繁琐,在java1.8后便更新了一个新的特性

即 lambda表达式

还是以上述为例子,我们再继续对匿名内部类的写法进行简化

package study.InnerClass;

public class Client2 {
    public static void main(String[] args) {
        OuterClass kupurk = new OuterClass();
        kupurk.run(()->System.out.println("lambda表达式简化匿名内部类"));
    }
}
public interface IRun {
    void fun();
}
public class OuterClass {
    public void run(IRun canshu)
    {
        canshu.fun();
    }
}

我们在main方法中省去了一大串的代码,即可得到相同的结果

还有带参数的lambda表达式

package study.InnerClass;

public class Client2 {
    public static void main(String[] args) {
        OuterClass kupurk = new OuterClass();
        kupurk.run(str->System.out.println(str+"吃饭"),"kupurk");
    }
}
public interface IRun {
    void fun(String name);
}
public class OuterClass {
    public void run(IRun canshu,String name)
    {
        canshu.fun(name);
    }
}

使用lamda表达式的条件:

函数式接口(只含有一个抽象方法的接口)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值