CMoney工程师战斗营weekly3

一山还有一山高课程难度有增无减的一周

上周老师说只要学完抽象类别後应该没有更难的东西,谁知道!!这周就出现了Lambda:((
在开始说明Lambda之前老师大约花了半小时左右讲解了内部类别还有半小时的匿名内部类,正当我开始回顾课程影片时..
当天下午,老师马上说:嗯~刚刚学的其实不太实用,我们把它全部丢掉吧!
我的脸:(;´༎ຶД༎ຶ`)ಥ_ಥ
然後就滔滔不绝地开始说明Lambda..

内部类别

可以在类别中再定义类别,称之为内部类别(Inner class)
内部类别通常只为了服务外部类别而存在时。

public class Test {(外)
    public class InnerTest {(内)
        
    }
}
public class Main {
    public static void main(String[] args) {
        Test test = new Test();//创建实体
        Test.InnerTest innerTest = test.new InnerTest();// 需要外部类别实例才能创建内部类别实例
    }
}

Test类别中宣告了另一个类别 InnerTest;InnerTest即为Test的内部类别。
在创建内部类别的实体时我们需要外部类别的实例才能创建内部类别实例,因为内部类别可以使用外部类别当前实例的属性与方法。

使用内部类别的好处

1.可以直接存取外部类别的私用(privat成员),举例来说,在视窗程序中,可以使用内部类别来实作一个事件倾听者类别,这个视窗倾听者类别可以直接存取视窗元件,而不用透过参数传递。
2.当某个slave类别只服务於一个Master类别,我们可将设定为内类别,如此使用Master的人就不知道slave的存在。
存取修饰子的使用:
外部类别只能使用:public、default、final、abstract
内部类别可以使用:private、protected、public、static

静态内部类

public class Test {
    public static class InnerTest {
    }
}
public class Main {
    public static void main(final String[] args) {
        final Test.InnerTest innerTest = new Test.InnerTest();// 无需依赖外部类别实体便可以被创建
    }
}

内部类别只为了服务外部类别而存在,但有时我们需要在尚未创建外部类别实体时独立创建内部类别实体。
静态内部类别不依赖外部类别实体,因此在静态内部类之中就无法使用外部类别.this来调用属性(因为不会有外部实体)
当然外部类别之中还是能存取内部类别包含private修饰的所有属性。

匿名内部类

产生一个匿名(没有名字)的类别来实现某个介面(或继承某个抽象类别),因为没有名字,所以只能建构一次。

public class Main {
    public static void main(final String[] args) {
        int a = 5;
        int b = 3;
        // 使用匿名内部类别创建实现Comparator的类别的实例
        Comparator comparator = new Comparator() {//创建後的实例我们使用Comparator的变数存取
            @Override//覆写原Comparator方法
            public int compareTo(int a, int b) {
                return a - b;
            }
        };
        System.out.println(comparator.compareTo(a, b));//通过变数调用该实例中的compareTo方法
}

在使用上匿名内部类别在产生出来後会直接创建出该类别的实例,此时可以选择使用变数存取(动态多型)或直接呼叫对应方法。

Lambda

只能使用於只有一个抽象方法的介面,称为Functional Interface(函式介面)。
Lambda 语法
//第一种:没有大括号,可以表达单行程序区块
(输入参数,输入参数,...) -> 单行逻辑程序区块
//第二种:大括号,可以表达多行程序区块
(输入参数,输入参数,...) -> { ... 多行程序区块 ...}
*Lambda最需要注意的是传入的参数对应接口以及执行的内容

String Pool

在Java中,String物件一但建立就无法改变(只能指向新的字串),且在程序之中,String占用记忆体非常大。
因此将String使用物件池方式来管理的收益非常高。
通过字串池(String pool)可以使相同字串得以被重复利用,以进一步达到节省空间的目的。

  • Java程序中比较两个String变数是否相同时,应该用equals(String s)

String s1 = "hello world";
String s2 = "hello world";

//s1及s2都是直接用双引号的方式来宣告,JVM在编译时看到这样的宣告会去String Pool里找是否有同样的字,没有的话会将字存入String Pool,若有的话则将储存字的位址返回。
//宣告s1时String Pool里面没有任何字,所以JVM会在String Pool的记忆体生一块位置来存放"hello world",然後将位址返回给s1
宣告s2时,JVM会先拿宣告的"hello world"去String Pool中看是否有存在相同的字,因为s1之前已经宣告过,所以JVM会将s1宣告的"hello world"记忆体位址返回给s2。

String s3 = new String("hello world");

//s3是用new关键字产生了一个String Pool外的新的记忆体位置来存放"hello world",与s1及s2的记忆体位址并不相同,所以s1 == s3结果为false。

String s4 = s3.intern();
//intern方法的作用是回传一个字串在字串池之中的引用。

System.out.println(s1 == s2); // true
//因为两个字串变数的值实际上都是指向同个记忆体位置的值。
System.out.println(s1 == s3); // false
System.out.println(s3 == s4); // false
System.out.println(s1 == s4); // true
//s4是s3呼叫intern()方法取得的值,该方法是拿s3指向的内容"hello world",去String Pool找是否有相同的内容,若有则回传String Pool该字的记忆体位址,与s1及s2指向的同一个位址,所以s1 == s4为true。
System.out.println(s1.equals(s3)); // true
System.out.println(s3.equals(s4)); // true


<<:  [Matplotlib] tight_layout()

>>:  推荐免费课程-【产业新尖兵全额补助】云端架构师培训班

4 游戏状态结构

上次我们讲到,服务器上的游戏状态会直接反应出游戏的画面。 而我们也需要随着游戏进行,依照动作与游戏规...

Day19 K平均演算法实作

https://github.com/PacktPublishing/Machine-Learni...

Day 12 实作资料库

前言 今天会实作资料库的结构。我们总共需要实作三个 table 的 scheme,分别是 users...

{CMoney战斗营} 的第八周 #如果我不再这里学习

游戏专题进行了半个月,耗费最大的心力是在处理碰撞的逻辑问题,为1 Pixcel的逻辑误差斤斤计较,不...

Day27 - 动态模型 part2 (LSTM with attention)

回顾一下昨天提到的,我们希望透过将 attention 机制加到 LSTM 中藉此找出每段语音中重要...