使用Java中的对象就涉及到几个方面:对象的初始化与清理、访问权限控制。想要“偷懒”就开始琢磨类的复用、变着魔法的多态、更自由的接口和藏起来的内部类。下面的思维导图大概只有我自己知道是啥了,书里面讲的很细致,连着把自己看激动后再看懵了,再到“哦,如此甚好”
以下是一些小记录。
初始化和清理
Java的初始化和创建捆绑再一起。
构造器与类同名
说到构造器与类同名这个事情,就会涉及到程序中的命名问题。任何程序设计语言都具备的一项重要特性就是对名字的运用。当创建一个对象时,也就给此对象分配到的存储空间取名字。方法就是给某个动作取的名字。
将人类语言中存在细微差别的概念“映射”到程序设计语言中时,相同的词可以表达多种不同的而含义,像C语言要求未每个方法都提供一个独一无二的标识符。由此带来的问题的解决方法就是重载
。 区分重载的标准是 独一无二的**参数类型**列表
this关键字
为了维护发送消息给对象的思路,内部的操作
class Banana { void peel(int i) { /* */} }
public class BananaPeel {
public static void main(String[] args) {
Banana a = new Banana();
Banana b = new Banana();
a.peel(1);
b.peel(2);
}
}
编译器偷偷摸摸把a.peel(1)
和b.peel(2)
的调用变成了Banana.peel(a, 1)
和Banana.peel(b, 2)
。
而this关键字能够知道调用者是谁!
终结处理和垃圾回收
finalize是用来解决“意外的”内存分配,实际测试的时候貌似调用System.gc()的时候并有没有调用。
finalize()一个有趣的用法:对象终结条件的验证。
访问权限控制
记住这一句好有道理的话:在任何相互关系中,具有关系所设计的各方都遵守的边界是十分重要的事情。访问控制让类的使用者更容易看到什么是重要的东西。
复用类
三种方式:组合、继承、代理。根据场景荤素搭配,好吃不贵。
多态
【#1 协变返回类型的实例】总是有些看上去不可思议却又理所当然的存在。
协变返回类型:在导出类中被“覆盖”的方法可以返回对应基类方法返回类型的导出类型。
好绕口,上代码:
class Grain {
@Override
public String toString() {
return "Grain";
}
}
class Wheat extends Grain {
@Override
public String toString() {
return "Wheat";
}
}
class Mill {
Grain process() {
return new Grain();
}
}
class WheatMill extends Mill {
Wheat process() {
return new Wheat();
}
}
public class CovariantReturn {
public static void main(String[] args){
Mill m = new Mill();
Grain g = m.process();
System.out.println(g);
m = new WheatMill();
g = m.process();
System.out.println(g);
}
}
// output
Grain
Wheat
接口
核心大概就是:任何抽象性都应该是应真正的需求而产生的,优先选择类而不是接口。
【#1 接口的实现类向上转型实例】。
可以向上转型为多种类型的示例:
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 {
public void swim() {}
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); u(h); v(h); w(h);
}
}
【#2 组合接口时的名称冲突示例】可以选择的时候不要作死就可以啦
interface I1 { void f(); }
interface I2 { int f(int i); }
interface I3 { int f(); }
class C { public int f() { return 0; } }
// 可以区分f的定义
class C2 implements I1,I2 {
public void f() {}
public int f(int) { return 1; } // overload
}
class C3 extends C implements I2 {
public int f(int i) { return 1; } // overload
}
class C4 extends C implements I3 {
public int f() { return 1; } // 可以省略。因为从C中继承得到I3的实现
}
// 无法区分
class C5 extends C implements I1 {} // 因为基类C中和I1中同名方法仅返回值不同,无法区分。
interface I4 extends I1,I3 {} // 因为I1和I3中的方法只有返回值的不同,无法区分开来
内部类
【#1 由private内部类带来的对于private的新的认识】:把对象交给认识它的人去处理
public interface E {
interface G {
void f();
}
public interface H {
void f();
}
void g();
}
class A {
interface B {
void f();
}
public class BImp implements B {
public void f() {}
}
private class BImp2 implements B {
public void f() {}
}
public interface C {
void f();
}
class CImp implements C {
public void f() {}
}
private class CImp2 implements C {
public void f() {}
}
interface D {
public void f();
}
private class DImp implements D {
public void f() {
System.out.println("DImp");
}
}
public class DImp2 implements D {
public void f() {}
}
public D getD() {
return new DImp();
}
private D dRef;
public void receiveD(D d) {
dRef = d;
dRef.f();
}
}
public class NestingInterfaces {
public class BImp implements A.B {
public void f() {}
}
class CImp implements A.C {
public void f() {}
}
class EImp implements E {
public void g() {}
}
class EGImp implements E.G {
public void f() {}
}
class EImpl2 implements E {
public void g() {}
class EG implements E.G {
public void f() {}
}
}
public static void main(String[] args){
A a = new A();
a.getD().f();
//a.receiveD(a.getD());
}
}
【#2 匿名类带参构造函数示例】
public Contents contents(int arg) {
return new Contents(arg) {
private int i = 11;
@Override
public int value() {
return i;
}
};
}
【#3 匿名类的构造器示例】
public Contents contents() {
return new Contents() {
{
System.out.println("initializer");
}
private int i = 11;
@Override
public int value() {
return i;
}
};
}
【#4 闭包示例】闭包是一个可调用的对象,包含创建它的作用域的信息。
class Callee1 implements Incrementable {
private int i = 0;
@Override
public void increment() {
i++;
System.out.println(i);
}
}
class MyIncrement {
public void increment() {
System.out.println("another operation.");
}
static void f(MyIncrement mi) {
mi.increment();
}
}
class Callee2 extends MyIncrement {
private int i = 0;
@Override
public void increment() {
super.increment();
i++;
System.out.println(i);
}
private class Closure implements Incrementable {
@Override
public void increment() {
Callee2.this.increment();
}
}
Incrementable getCallbackReference() {
return new Closure();
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) {
callbackReference = cbh;
}
void go() {
callbackReference.increment();
}
}
public class Callbacks {
public static void main(String[] args){
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
// caller1.go();
// caller1.go();
caller2.go();
caller2.go();
}
}
感觉示例给的有点尴尬,Callee2直接implement Increment也是OK的,可能主要是为了演示钩子吧。
【#5 内部类的继承示例】
class WithInner {
class Inner {}
}
public class InheritInner extends WithInner.Inner {
InheritInner(WithInner wi) {
wi.supper();
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner ii = new InheritrInner(wi);
}
}
总结
刚看的时候总觉得和C++虚函数丫啥的很像,轻松瞥了几眼。呜呼~仔细看完示例就会发现用法十分灵活而且很多,虽然目前还无法描述出来,至少会觉得,到目前为止,Java的这些特性都是依着一套准则来的。请继续吧!