2022.2.19
第十章 接口
-
接口(该接口的修饰符是默认)如果只有包访问权限的话,那么包外的类是无法实现这个接口的,即便这个接口里是public方法
-
其实这里我是没太理解作者的意思的,不过就我目前测试的结果,其实接口直接默认确实是最好的选择,因为接口没有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(); }
-
讲道理,第二句话就使得接口有了类的特征了,而且很诡异,这么搞有什么意义,如果设为了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. } @Override private 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/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/Adventure.java // Multiple interfaces interface CanFight { void fight(); } interface CanSwim { void swim(); } interface CanFly { void fly(); } class ActionCharacter { public void fight() {} } class Hero extends ActionCharacter implements 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();
-
// 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.java interface 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, 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
第十章 接口
-
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"); } }
首先要想这么用得先导包,我提前用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"); } }
-
看了很久,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; } } }
-
看了这么多接口的内容,现在就感觉接口就像游戏中的法师,如果要调用火元素来进行攻击,就必须动用火元素魔法的咒语,而这个咒语就是接口,而再打比方,就是你想要用特效为暴击的魔法攻击,而不同元素实现暴击的方式可以不一样,但表现出来的结果就是暴击,而这个特效为暴击的魔法攻击实际上也就是接口.
-
我看不出来为什么工厂会有这种作用,境界还是太低了
我自己只能理解到工厂将接口和实现代码完全的分离了,这里的分离指的仅仅只是Game接口和实现Game接口的类,因为这里的Game接口简单,但我用来实现的那个类不一定简单,他可能远比这个复杂得多,而工厂化给出接口类,我自己更便偏向于易读性
-
这个结构还挺有意思,虽然感觉没啥软用
-
忽然感觉这玩意是专门为了针对向上转型吗?
package example; public class one implements a{ String s1 = "hello"; public one (String s1){ this.s1 = s1; } @Override public 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 {}
不过我试了下,编译是能过的,看不懂为什么要有这种新特性
重看了一遍,这个应该是为了画图的时候好画,因为它的修饰符就那么几个,这样就可以使类的层次结构更加鲜明,不过不可否认的是,这样的可拓展性我更感觉还是不太行
第十一章 内部类
-
这里如果不在包外的话,可以直接这么写
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/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() */
学习如何通过内部类返回外部类
-
看了半天,才发现我看错了,作者下面解释的那个是用了内部类创建了外部类,再用外部类对应的方法去生成内部类,而这种创建方法本身逻辑就有点不自洽
其他
- bit等于一个二进制位
- java的switch的使用https://www.w3schools.com/java/java_switch.asp