日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

on java8学习笔记2022.2.19-2022.2.20

發布時間:2024/4/18 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 on java8学习笔记2022.2.19-2022.2.20 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2022.2.19

第十章 接口

  • 如果一個類并不需要包含抽象方法,但同時還想阻止對它的任何實例化,這時將其定義為抽象類就很有用了。

  • 接口和抽象類之間最顯著的區別可能是兩者的慣用方式。接口通常暗示“類的類型”或作為形容詞來使用,例如Runnable或Serializable,而抽象類通常是類層次結構的一部分,并且是“事物的類型”,例如String或Instrument。

  • 接口也可以包含字段,但這些字段是隱式的static和final。

  • 接口(該接口的修飾符是默認)如果只有包訪問權限的話,那么包外的類是無法實現這個接口的,即便這個接口里是public方法

  • 你可以選擇將接口中的方法顯式聲明為public,但即使不顯式聲明,它們也是public的。所以當實現一個接口時,來自接口的方法必須被定義為public。否則,它們將默認為包訪問權限,導致在繼承期間降低了方法的可訪問性,而這是Java編譯器不允許的。

    其實這里我是沒太理解作者的意思的,不過就我目前測試的結果,其實接口直接默認確實是最好的選擇,因為接口沒有private這種東西,也沒有protected這種東西,實際上就是默認和public,而當接口是public時,它的方法本身就全部默認是public的,而默認的時候就全部內置默認,非常和諧,而接口本身就是為了描述類所共有的特征的,所有類的方法的這么個東西,所以訪問權限一致我倒是覺得挺合理的

    package Test;import example.a; import example.one;public class test implements a {public static void main(String[] args){new test().function();}public void function(){System.out.println("hello");} } package example;public interface a {void function(); }
  • 添加默認方法的一個令人信服的原因是,它允許向現有接口中添加方法,而不會破壞已經在使用該接口的所有代碼。默認方法有時也稱為防御方法(defender method)或虛擬擴展方法(virtual extension method)。

    在JDK 9中,接口里的default和static方法都可以是private的。

    講道理,第二句話就使得接口有了類的特征了,而且很詭異,這么搞有什么意義,如果設為了private,接口外的都無法訪問這個方法,那我設置這個方法是要干嘛?注意,我的意思是這個接口對實現類是直接隱藏的,因為不是有默認final這個東西,真的讓人頭大,比如下面這個

    package example;public interface a {private void b(){System.out.println("hello");}} package example; public class one implements a{String s1 = "hello";public one (String s1){this.s1 = s1;}public static void main(String[] args){System.out.println(new two("second"));a b = new one();b.}@Overrideprivate void b(){} }

    關注下@Override,會發現,它提示你未從超類重寫方法,而下面的代碼顯示了你在包外無法調用接口a的私有靜態方法,這導致我看不懂這個私有靜態方法有什么用,當然,同時編譯器也會告訴你接口中的方法多余.

    package example; public class one implements a{String s1 = "hello";public one (String s1){this.s1 = s1;}public static void main(String[] args){a.c();} } package example;public interface a {private static void b(){System.out.println("hello");}public static void c(){System.out.println("hi");} }
  • // interfaces/MultipleInheritance.java import java.util.*;interface One { default void first() { System.out.println("first"); } }interface Two { default void second() { System.out.println("second"); } }interface Three { default void third() { System.out.println("third"); } }class MI implements One, Two, Three {}public class MultipleInheritance { public static void main(String[] args) { MI mi = new MI(); mi.first(); mi.second(); mi.third(); } } /* 輸出: first second third */ // interfaces/MICollision.java import java.util.*;interface Bob1 { default void bob() { System.out.println("Bob1::bob"); } }interface Bob2 { default void bob() { System.out.println("Bob2::bob"); } }// class Bob implements Bob1, Bob2 {} /* 產生: error: class Bob inherits unrelated defaults for bob() from types Bob1 and Bob2 class Bob implements Bob1, Bob2 {} ^ 1 error */interface Sam1 { default void sam() { System.out.println("Sam1::sam"); } }interface Sam2 { default void sam(int i) { System.out.println(i * 2); } }// 這里能正常工作是因為參數列表不同 class Sam implements Sam1, Sam2 {}interface Max1 { default void max() { System.out.println("Max1::max"); } }interface Max2 { default int max() { return 47; } }// class Max implements Max1, Max2 {} /* 產生: error: types Max2 and Max1 are incompatible; both define max(), but with unrelated return types class Max implements Max1, Max2 {} ^ 1 error */

    這里要解決的話就只能重寫

  • 返回類型不是方法簽名的一部分

  • // interfaces/Jim.java import java.util.*;interface Jim1 {default void jim() {System.out.println("Jim1::jim");} }interface Jim2 {default void jim() {System.out.println("Jim2::jim");} }public class Jim implements Jim1, Jim2 {@Override public void jim() {Jim2.super.jim();}public static void main(String[] args) {new Jim().jim();} } /* 輸出: Jim2::jim */

    不是很清楚為什么這里一定要加個super,如果不加的話,會報錯,當然,也可以這么寫

    package example; // interfaces/Jim.java import java.util.*;interface Jim1 {default void jim() {System.out.println("Jim1::jim");} }interface Jim2 {default void jim() {System.out.println("Jim2::jim");} }public class Jim implements Jim1, Jim2 {@Override public void jim() {System.out.println("hello");}public static void main(String[] args) {new Jim().jim();} }

    有可能那個交給它基類寫去了?誰知道呢

  • // interfaces/MetalWork.java import onjava.Operation;class Heat implements Operation {@Override public void execute() {Operation.show("Heat");} }public class MetalWork {public static void main(String[] args) {// 必須在靜態上下文中定義才能使用方法引用Operation twist = new Operation() {public void execute() {Operation.show("Twist");}};Operation.runOps(new Heat(), // [1]new Operation() { // [2]public void execute() {Operation.show("Hammer");}},twist::execute, // [3]() -> Operation.show("Anneal") // [4]);} } /* 輸出: Heat Hammer Twist Anneal */ // onjava/Operation.java package onjava;public interface Operation {void execute();static void runOps(Operation... ops) {for(Operation op : ops)op.execute();}static void show(String msg) {System.out.println(msg);} }

    這個看了挺久的,除了最后一個lambda沒學過以外,其他大概看懂了,第一個是上面已經定義好的類,第二個是以接口定義的類,第三個是方法引用.

    這里讓我比較新奇的就是匿名的接口類的定義方式了

    怎么看這個匿名接口類的定義方法呢?首先將new先隔開,那么后面Operation就是定義接口中需要我們定義的方法,而那個new則是創建這個對象

    Operation() {public void execute() {Operation.show("Twist");}}

    這里沒有構造器,應該調用的默認構造器

    {public void execute() {Operation.show("Twist");}}
  • > ```java > // interfaces/interfaceprocessor/Processor.java > package interfaces.interfaceprocessor; > > public interface Processor { > default String name() { > return getClass().getSimpleName(); > } > Object process(Object input); > } > // interfaces/interfaceprocessor/Applicator.java > package interfaces.interfaceprocessor; > > public class Applicator { > public static void apply(Processor p, Object s) { > System.out.println("Using Processor " + p.name()); > System.out.println(p.process(s)); > } > } > ``` > > 復用代碼的第一種方法是,調用者可以編寫符合這個接口的類,如下所示: > > ```java > // interfaces/interfaceprocessor/StringProcessor.java > // {java interfaces.interfaceprocessor.StringProcessor} > package interfaces.interfaceprocessor; > import java.util.*; > > interface StringProcessor extends Processor { > @Override > String process(Object input); // [1] > String S = // [2] > "If she weighs the same as a duck, " + > "she's made of wood"; > static void main(String[] args) { // [3] > Applicator.apply(new Upcase(), S); > Applicator.apply(new Downcase(), S); > Applicator.apply(new Splitter(), S); > } > } > > class Upcase implements StringProcessor { > @Override // 協變返回 > public String process(Object input) { > return ((String)input).toUpperCase(); > } > } > > class Downcase implements StringProcessor { > @Override > public String process(Object input) { > return ((String)input).toLowerCase(); > } > } > > class Splitter implements StringProcessor { > @Override > public String process(Object input) { > return Arrays.toString(((String)input).split(" ")); > } > } > /* 輸出: > Using Processor Upcase > IF SHE WEIGHS THE SAME AS A DUCK, SHE'S MADE OF WOOD > Using Processor Downcase > if she weighs the same as a duck, she's made of wood > Using Processor Splitter > [If, she, weighs, the, same, as, a, duck,, she's, made, > of, wood] > */ > ``` > > [1] 這個聲明是不必要的,如果刪除它,編譯器也不會提示錯誤。但它能指出方法的返回值從`Object`協變為`String`。 > [2] 字段`s`自動是`static`和`final`的,因為它是在接口內定義的。 > [3] 你甚至可以在接口中定義一個`main()`方法。接口繼承接口,我只能說好家伙,還有一個默認的main()方法,真是把我秀到了```java package example;public interface a {private static void b(){System.out.println("hello");}static void c(){System.out.println("hi");}static void main(String[] args) {b();} } ``````java package example; public class one implements a{String s1 = "hello";public one (String s1){this.s1 = s1;}public static void main(String[] args){a.c();a.main(args);} } ```忽然間我就懂怎么用這個詭異的private的方法了,把他嵌套再這個接口的其他public方法里
  • // interfaces/interfaceprocessor/FilterProcessor.java // {java interfaces.interfaceprocessor.FilterProcessor} package interfaces.interfaceprocessor; import interfaces.filters.*;class FilterAdapter implements Processor { Filter filter; FilterAdapter(Filter filter) {this.filter = filter; } @Override public String name() { return filter.name(); } @Override public Waveform process(Object input) {return filter.process((Waveform)input); } }public class FilterProcessor { public static void main(String[] args) {Waveform w = new Waveform();Applicator.apply(new FilterAdapter(new LowPass(1.0)), w);Applicator.apply(new FilterAdapter(new HighPass(2.0)), w);Applicator.apply(new FilterAdapter(new BandPass(3.0, 4.0)), w); } } /* 輸出: Using Processor LowPass Waveform 0 Using Processor HighPass Waveform 0 Using Processor BandPass Waveform 0 */

    在使用適配器的實現方式里,FilterAdapter構造器通過你擁有的Filter接口,來生成一個你需要的Processor接口的對象。你可能還會注意到FilterAdapter類中使用了委托。

    協變允許我們從process()里產生一個Waveform,而不僅僅是一個Object。

    接口與實現的解耦允許我們將一個接口應用于多個不同的實現,因此代碼更具可復用性。

    挺騷的,我現在看委托越來越感覺像是在玩代理

  • // interfaces/Adventure.java // Multiple interfacesinterface CanFight {void fight(); }interface CanSwim {void swim(); }interface CanFly {void fly(); }class ActionCharacter {public void fight() {} }class Hero extends ActionCharacterimplements CanFight, CanSwim, CanFly {@Override public void swim() {}@Override public void fly() {} }public class Adventure {public static void t(CanFight x) { x.fight(); }public static void u(CanSwim x) { x.swim(); }public static void v(CanFly x) { x.fly(); }public static void w(ActionCharacter x) { x.fight(); }public static void main(String[] args) {Hero h = new Hero();t(h); // 當作一個CanFight類型u(h); // 當作一個CanSwim類型v(h); // 當作一個CanFly類型w(h); // 當作一個ActionCharacter類型} }

    發現我搞混了一個東西,如果是下面這種形式

    public void fun(){}

    上面這種表示的是一個默認方法,也就是他不是abstract的,下面這種才是抽象方法的寫法

    public void fun();
  • 這就帶來了一個問題:應該使用接口還是抽象類?如果可以在沒有任何方法定義或成員變量的情況下創建基類,那么就使用接口而非抽象類。事實上,如果你認為某個類可以作為基類的話,也就可以考慮把它設計成接口(在10.11節中會重新討論這個主題)。\

  • // interfaces/HorrorShow.java // 通過繼承來擴展接口interface Monster {void menace(); }interface DangerousMonster extends Monster {void destroy(); }interface Lethal {void kill(); }class DragonZilla implements DangerousMonster {@Override public void menace() {}@Override public void destroy() {} }interface Vampire extends DangerousMonster, Lethal {void drinkBlood(); }class VeryBadVampire implements Vampire {@Override public void menace() {}@Override public void destroy() {}@Override public void kill() {}@Override public void drinkBlood() {} }public class HorrorShow {static void u(Monster b) { b.menace(); }static void v(DangerousMonster d) {d.menace();d.destroy();}static void w(Lethal l) { l.kill(); }public static void main(String[] args) {DangerousMonster barney = new DragonZilla();u(barney);v(barney);Vampire vlad = new VeryBadVampire();u(vlad);v(vlad);w(vlad);} }

    注意下,這里Vampire一次性繼承了大量的接口,但是,這是接口特有的屬性,類不能這樣

  • // interfaces/InterfaceCollision.javainterface I1 { void f(); } interface I2 { int f(int i); } interface I3 { int f(); } class C { public int f() { return 1; } }class C2 implements I1, I2 { @Override public void f() {} @Override public int f(int i) { return 1; } // 重載 }class C3 extends C implements I2 { @Override public int f(int i) { return 1; } // 重載 }class C4 extends C implements I3 { // 完全相同,沒有問題: @Override public int f() { return 1; } }// 方法只有返回類型不同 //- class C5 extends C implements I1 {} //- interface I4 extends I1, I3 {}

    之所以出現問題,是因為重寫、實現和重載令人不快地混合在一起。此外,重載方法不能只有返回類型不同。當最后兩行取消注釋時,錯誤消息說明了一切:

    error: C5 is not abstract and does not override abstract method f() in I1 class C5 extends C implements I1 {}error: types I3 and I1 are incompatible; both define f(), but with unrelated return types interface I4 extends I1, I3 {}

    這里我還是有點意外的,原來重載方法只有返回類型不同真會報錯,我把這個改成了下面這個就不會報錯了

    // interfaces/InterfaceCollision.javainterface I1 { void f(); } interface I2 { int f(int i); } interface I3 { int f(); } class C { public int f() { return 1; } }class C2 implements I1, I2 {@Overridepublic void f() {}@Overridepublic int f(int i) { return 1; } // 重載 }class C3 extends C implements I2 {@Overridepublic int f(int i) { return 1; } // 重載 }class C4 extends C implements I3 {// 完全相同,沒有問題:@Override public int f() { return 1; } }// 方法只有返回類型不同 //class C5 extends C implements I1 {} interface I4 extends I1, I2 {}

    然后我這里思考了一下,參數全部一樣,返回類型居然不一樣確實很離譜,這就不就變成抽獎了,而且你這樣實現也會很為難,讓人無法理解

  • 下面代碼展示了final修飾的變量必須被初始化,否則報錯

    package example; public final class one implements a{public final int i ;public String s1 = "hello";public one (String s1){this.s1 = s1;}public static void main(String[] args){one a = new one("fhdjahj");a.s1="hello world";System.out.println(a.i);} }

    只要將final去掉,那么輸出結果就是0,否則你編譯都過不去

  • 2022.2.20

    第十章 接口

  • 接口中的任何字段都自動是static和final的,因此接口是創建一組常量值的便捷工具。

  • package Test;import example.a; import example.one; import example.*; public class test {public static void main(String[] args){//new test().function();System.out.println(Months.JANUARY);}public void function(){System.out.println("hello");} } package example;public interface Months {intJANUARY = 1, FEBRUARY = 2, MARCH = 3,APRIL = 4, MAY = 5, JUNE = 6, JULY = 7,AUGUST = 8, SEPTEMBER = 9, OCTOBER = 10,NOVEMBER = 11, DECEMBER = 12; }

    首先要想這么用得先導包,我提前用idea,怎么導Months都不對,所以把他放進了我自己創建的包里面去了,然后我實驗了一下,確實已經被默認修改成了final

    package Test;import example.a; import example.one; import example.*; public class test {public static void main(String[] args){//new test().function();Months.JANUARY=2;}public void function(){System.out.println("hello");} }
  • 這些字段不是接口的一部分。這些值存儲在該接口的靜態存儲區中。

  • 接口可以嵌套在類和其他接口中。這呈現了幾個有趣的特性:

    // interfaces/nesting/NestingInterfaces.java // {java interfaces.nesting.NestingInterfaces} package interfaces.nesting;class A { interface B {void f(); } public class BImp implements B {@Override public void f() {} } private class BImp2 implements B {@Override public void f() {} } public interface C {void f(); } class CImp implements C {@Override public void f() {} } private class CImp2 implements C {@Override public void f() {} } private interface D {void f(); } private class DImp implements D {@Override public void f() {} } public class DImp2 implements D {@Override public void f() {} } public D getD() { return new DImp2(); } private D dRef; public void receiveD(D d) {dRef = d;dRef.f(); } }interface E { interface G {void f(); } // 多余的public: public interface H {void f(); } void g(); // 接口內不能用private //- private interface I {} }public class NestingInterfaces { public class BImp implements A.B {@Override public void f() {} } class CImp implements A.C {@Override public void f() {} } // private的接口只能在定義的類里實現: //- class DImp implements A.D { //- public void f() {} //- } class EImp implements E {@Override public void g() {} } class EGImp implements E.G {@Override public void f() {} } class EImp2 implements E {@Override public void g() {}class EG implements E.G {@Override public void f() {}} } public static void main(String[] args) {A a = new A();// 無法訪問A.D://- A.D ad = a.getD();// 只能返回A.D://- A.DImp2 di2 = a.getD();// 無法訪問該接口的方法//- a.getD().f();// 另一個A才能處理getD():A a2 = new A();a2.receiveD(a.getD()); } }

    在類中嵌套接口的語法相當明顯。就像非嵌套接口一樣,它們可以具有public或包訪問權限的可見性。

    另外這里有個不易理解之處:接口也可以是private的,如A.D中所示(嵌套接口和嵌套類使用相同的限定語法)。private的嵌套接口有什么好處?你可能會猜測,它只能作為DImp中的私有內部類來實現,但是A.DImp2表明它也可以作為public類來實現。不過A.DImp2在使用時只能被視為自身的類型,你不能提及它實現了private的接口D。所以實現了private接口的話,可以在不添加任何類型信息的情況下,限定該接口中的方法定義(也就是說,不允許任何向上轉型)。

    方法getD()讓我們進一步陷入困境,這與private接口有關:它是一個public方法,但返回了一個private接口的引用。可以對這個方法的返回值做些什么?在main()里我們多次嘗試使用該返回值,但都失敗了。該返回值必須傳遞給一個有權使用它的對象——這里是另一個A,它可以通過receiveD()方法使用這個返回值。

    接口E表明,接口之間也可以嵌套。然而,關于接口的規則——特別是所有接口元素必須是public的——在這里是嚴格執行的,所以嵌套在另一個接口中的接口自動為public的,不能設為private。

    NestingInterfaces展示了實現嵌套接口的各種方式。特別要注意的是,當實現一個接口時,并不需要實現嵌套在其中的接口。此外,private接口不能在它們的定義類之外實現。

    初看起來,這些特性好像僅僅是為了語法一致性而添加的,但我通常發現,一旦了解了一個特性,你就會經常發現它的有用之處。

    看了很久,D那里應該說的是因為接口D是private的,也就是只在類A中可見,那么你就不能寫成這個形式了

    A.D a = new Dimp();

    很有意思的一點,一個默認類里面居然定義了一個公共類,不過我試了下,這個公共類實際上還是出不了包

    package Test;import example.a; import example.one; import example.*; public class test {public static void main(String[] args){//new test().function();System.out.println(new three.four());}public void function(){System.out.println("hello");} } package example; public final class one implements a{public int i ;public String s1 = "hello";public one (String s1){this.s1 = s1;}public static void main(String[] args){one a = new one("fhdjahj");a.s1="hello world";System.out.println(a.i);} } class three {public class four {String s1 = "hello world";static{System.out.println("hello");}public String toString(){return s1;}} } package example; public final class one implements a{public int i ;public String s1 = "hello";public one (String s1){this.s1 = s1;}public static void main(String[] args){one a = new one("fhdjahj");a.s1="hello world";System.out.println(a.i);} } class three {public class four {String s1 = "hello world";static{System.out.println("hello");}public String toString(){return s1;}} }
  • 看了這么多接口的內容,現在就感覺接口就像游戲中的法師,如果要調用火元素來進行攻擊,就必須動用火元素魔法的咒語,而這個咒語就是接口,而再打比方,就是你想要用特效為暴擊的魔法攻擊,而不同元素實現暴擊的方式可以不一樣,但表現出來的結果就是暴擊,而這個特效為暴擊的魔法攻擊實際上也就是接口.

  • 接口是通向多個實現的網關,如果想生成適合某個接口的對象,一種典型的方式是工廠方法(Factory Method)設計模式。你不是直接調用構造器,而是在工廠對象上調用創建方法,它可以產生接口實現。這樣,理論上,你的代碼與接口實現完全隔離,從而可以透明地將一種實現替換為另一種實現。下面是一個示例,展示了工廠方法的結構:

    // interfaces/Factories.javainterface Service { void method1(); void method2(); }interface ServiceFactory { Service getService(); }class Service1 implements Service { Service1() {} // 包訪問權限 @Override public void method1() {System.out.println("Service1 method1"); } @Override public void method2() {System.out.println("Service1 method2"); } }class Service1Factory implements ServiceFactory { @Override public Service getService() {return new Service1(); } }class Service2 implements Service { Service2() {} // 包訪問權限 @Override public void method1() {System.out.println("Service2 method1"); } @Override public void method2() {System.out.println("Service2 method2"); } }class Service2Factory implements ServiceFactory { @Override public Service getService() {return new Service2(); } }public class Factories { public static void serviceConsumer(ServiceFactory fact) {Service s = fact.getService();s.method1();s.method2(); } public static void main(String[] args) {serviceConsumer(new Service1Factory());// 服務是完全可以互換的:serviceConsumer(new Service2Factory()); } } /* 輸出: Service1 method1 Service1 method2 Service2 method1 Service2 method2 */

    如果沒有工廠方法,你的代碼必須在某處指定創建Service的確切類型,以調用相應的構造器。

    為什么要添加這種額外的間接層?一個常見的原因是創建框架。假設你正在創建一個系統來玩游戲,例如想要在同一個棋盤上玩國際象棋和跳棋:

    // interfaces/Games.java // 一個使用了工廠方法的游戲框架interface Game { boolean move(); } interface GameFactory { Game getGame(); }class Checkers implements Game { private int moves = 0; private static final int MOVES = 3; @Override public boolean move() {System.out.println("Checkers move " + moves);return ++moves != MOVES; } }class CheckersFactory implements GameFactory { @Override public Game getGame() { return new Checkers(); } }class Chess implements Game { private int moves = 0; private static final int MOVES = 4; @Override public boolean move() {System.out.println("Chess move " + moves);return ++moves != MOVES; } }class ChessFactory implements GameFactory { @Override public Game getGame() { return new Chess(); } }public class Games { public static void playGame(GameFactory factory) {Game s = factory.getGame();while(s.move()); } public static void main(String[] args) {playGame(new CheckersFactory());playGame(new ChessFactory()); } } /* 輸出: Checkers move 0 Checkers move 1 Checkers move 2 Chess move 0 Chess move 1 Chess move 2 Chess move 3 */

    如果Games類代表了一段復雜的代碼,這種方式意味著你可以在不同類型的游戲中復用該代碼。可以想象,更加復雜的游戲可以從這種模式中受益。

    在下一章中,你將看到實現工廠方法的更優雅的方式,那就是使用匿名內部類。

    我看不出來為什么工廠會有這種作用,境界還是太低了

    我自己只能理解到工廠將接口和實現代碼完全的分離了,這里的分離指的僅僅只是Game接口和實現Game接口的類,因為這里的Game接口簡單,但我用來實現的那個類不一定簡單,他可能遠比這個復雜得多,而工廠化給出接口類,我自己更便偏向于易讀性

  • sealed類的子類只能通過下面的某個修飾符來定義。

    • final:不允許有進一步的子類。
    • sealed:允許有一組密封子類。
    • non-sealed:一個新關鍵字,允許未知的子類來繼承它。
  • // interfaces/SealedSubclasses.java // {NewFeature}從JDK 17開始sealed class Bottom permits Level1 {} sealed class Level1 extends Bottom permits Level2 {} sealed class Level2 extends Level1 permits Level3 {} final class Level3 extends Level2 {}

    注意,一個sealed類必須至少有一個子類。

    這個結構還挺有意思,雖然感覺沒啥軟用

  • 一個sealed的基類無法阻止non-sealed的子類的使用,因此可以隨時放開限制:

    // interfaces/NonSealed.java // {NewFeature} 從JDK 17開始sealed class Super permits Sub1, Sub2 {} final class Sub1 extends Super {} non-sealed class Sub2 extends Super {} class Any1 extends Sub2 {} class Any2 extends Sub2 {}

    Sub2允許任意數量的子類,因此它似乎放開了對可以創建的類型的控制。但是,我們還是嚴格限制了sealed類Super的直接子類。也就是說,Super仍然只能有直接子類Sub1和Sub2。

    忽然感覺這玩意是專門為了針對向上轉型嗎?

    package example; public class one implements a{String s1 = "hello";public one (String s1){this.s1 = s1;}@Overridepublic void cd() {;}public static void main(String[] args){a.c();a.main(args);Super first = new Any1();} } sealed class Super permits Sub1, Sub2 {} final class Sub1 extends Super {} non-sealed class Sub2 extends Super {} class Any1 extends Sub2 {} class Any2 extends Sub2 {}

    不過我試了下,編譯是能過的,看不懂為什么要有這種新特性

    重看了一遍,這個應該是為了畫圖的時候好畫,因為它的修飾符就那么幾個,這樣就可以使類的層次結構更加鮮明,不過不可否認的是,這樣的可拓展性我更感覺還是不太行

  • // interfaces/PermittedSubclasses.java // {NewFeature}從JDK 17開始sealed class Color permits Red, Green, Blue {} final class Red extends Color {} final class Green extends Color {} final class Blue extends Color {}public class PermittedSubclasses { public static void main(String[] args) {for(var p: Color.class.getPermittedSubclasses())System.out.println(p.getSimpleName()); } } /* 輸出: Red Green Blue */
  • 我們可能很容易就會覺得接口是好的,因此總是選擇接口而不是具體的類。幾乎任何要創建一個類的場景,都可以創建一個接口和一個工廠來代替。

    許多人受到了這種誘惑,只要有可能就創建接口和工廠。這里的邏輯似乎是,你可能會用到不同的實現,因此應該始終添加這層抽象。這是一種過早的設計優化。

    任何抽象都應該由真正的需求來驅動。接口應該是在必要時用來重構的東西,而不是在任何地方都多加一個間接層級,進而帶來額外的復雜性。這種額外的復雜性影響很大,如果你讓某人在克服這種復雜性上花費時間,而他最終卻發現你添加接口只不過是為了“以防萬一”,而非出于什么令人信服的其他理由——那好吧,如果我看到這樣的設計,就會開始質疑這個人做過的其他所有設計。

    一個比較恰當的指導方針是“優先使用類而不是接口”。從類開始設計,如果很明顯接口是必要的,那么就重構。接口是一個很好的工具,但它很容易被濫用。

  • 第十一章 內部類

  • 更普遍的情況是,外部類有一個方法,該方法返回一個指向內部類的引用,正如在to()和contents()方法中看到的那樣。

    // innerclasses/Parcel2.java // 返回一個指向內部類的引用public class Parcel2 { class Contents {private int i = 11;public int value() { return i; } } class Destination {private String label;Destination(String whereTo) {label = whereTo;}String readLabel() { return label; } } public Destination to(String s) {return new Destination(s); } public Contents contents() {return new Contents(); } public void ship(String dest) {Contents c = contents();Destination d = to(dest);System.out.println(d.readLabel()); } public static void main(String[] args) {Parcel2 p = new Parcel2();p.ship("Tasmania");Parcel2 q = new Parcel2();// 定義指向內部類的引用:Parcel2.Contents c = q.contents();Parcel2.Destination d = q.to("Borneo"); } } /* 輸出: Tasmania */

    要在外部類的非靜態方法之外的任何地方創建內部類的對象,必須像在main()中看到的那樣,將對象的類型指定為OuterClassName.InnerClassName。

    這里如果不在包外的話,可以直接這么寫

    public class Parcel2 {class Contents {private int i = 11;public int value() { return i; }}class Destination {private String label;Destination(String whereTo) {label = whereTo;}String readLabel() { return label; }}public Destination to(String s) {return new Destination(s);}public Contents contents() {return new Contents();}public void ship(String dest) {Contents c = contents();Destination d = to(dest);System.out.println(d.readLabel());}public static void main(String[] args) {Parcel2 p = new Parcel2();p.ship("Tasmania");Parcel2 q = new Parcel2();// 定義指向內部類的引用:Contents c = q.contents();Destination d = q.to("Borneo");} }
  • // innerclasses/Sequence.java // 保存一個對象序列interface Selector { boolean end(); Object current(); void next(); }public class Sequence { private Object[] items; private int next = 0; public Sequence(int size) {items = new Object[size]; } public void add(Object x) {if(next < items.length)items[next++] = x; } private class SequenceSelector implements Selector {private int i = 0;@Overridepublic boolean end() { return i == items.length; }@Overridepublic Object current() { return items[i]; }@Overridepublic void next() { if(i < items.length) i++; } } public Selector selector() {return new SequenceSelector(); } public static void main(String[] args) {Sequence sequence = new Sequence(10);for(int i = 0; i < 10; i++)sequence.add(Integer.toString(i));Selector selector = sequence.selector();while(!selector.end()) {System.out.print(selector.current() + " ");selector.next();} } } /* 輸出: 0 1 2 3 4 5 6 7 8 9 */

    Sequence是以類的形式包裝起來的定長Object數組。可以調用add()向序列末尾增加一個新的Object(如果還有空間)。要取得 Sequence中的每一個對象,可以使用名為Selector的接口。這是迭代器(Iterator)設計模式的一個例子,我們會在第12章進一步學習。通過Selector,可以檢查是否到了Sequence的末尾(end()),訪問當前Object(current()),以及移動到下一個Object(next())。因為Selector是一個接口,所以其他類可以用自己的方式實現該接口,而且其他方法可以以該接口為參數,來創建更通用的代碼。

    人看麻了,有點工廠化方法的味道

  • 內部類的對象在構造時,需要一個指向外圍類對象的引用,如果編譯器無法訪問這個引用,它就會報錯。不過這種情況大多不需要程序員干預。

    有一點味道了,因為內部類的對象是從屬于他的外部對象的

  • // innerclasses/DotThis.java // 訪問外部類對象public class DotThis {void f() { System.out.println("DotThis.f()"); } public class Inner {public DotThis outer() {return DotThis.this;// 如果直接寫“this”,引用的會是Inner的“this”} }public Inner inner() { return new Inner(); } public static void main(String[] args) {DotThis dt = new DotThis(); DotThis.Inner dti = dt.inner(); dti.outer().f();} } /* 輸出: DotThis.f() */

    學習如何通過內部類返回外部類

  • // innerclasses/DotNew.java // 使用.new語法直接創建一個內部類的對象public class DotNew { public class Inner {} public static void main(String[] args) {DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner(); } }

    要直接創建內部類的對象,你可能會以為,要遵循和前面同樣的形式,使用外部類的名字DotNew,然而事實并非如此。我們要使用外部類的對象來創建內部類的對象,正如我們在示例代碼中所看到的那樣。這也解決了內部類的名字作用域問題,所以我們不用dn.new DotNew.Inner()(確實也不能用)。

    看了半天,才發現我看錯了,作者下面解釋的那個是用了內部類創建了外部類,再用外部類對應的方法去生成內部類,而這種創建方法本身邏輯就有點不自洽

  • 其他

  • bit等于一個二進制位
  • java的switch的使用https://www.w3schools.com/java/java_switch.asp
  • 總結

    以上是生活随笔為你收集整理的on java8学习笔记2022.2.19-2022.2.20的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。