zoukankan      html  css  js  c++  java
  • 《Think in Java》笔记I

    前面四章没啥好写的,都是些很基础的东西

    第五章笔记:初始化与清理

    5.2 区分重载方法:

      每个重载方法都会有一个独一无二的参数类型列表,当然也可以已返回值区分重载方法。

    5.5.4 Java虚拟机采用的是一种自适应的垃圾回收技术

      有一种名为停止-复制,即先暂停程序的运行(所以它不属于后台回收模式),然后将所有存活的的对象从当前堆复制到另一个堆,没有复制的就是垃圾了。当对象被复制到新堆时,它们是一个挨着一个以新堆保持紧凑排列,然后就可以按前述方法简单、直接的分配内存了。

      标记-清扫模式依据的思路同样是从堆栈和静态存储区出发,遍历所有的引用,进而找出所有存活的对象。每当找到一个存活的对象,就给对象设一个标记,这个过程不会回收任何对象。只有当全部标记工作完成的时候,清理工作才会开始。在清理过程中,没有标记的对象将被释放,不会发生任何复制工作。所以剩下的堆空间是不连续的,垃圾回收期要是希望得到连续空间的话,就得重新整理剩下的对象。

    5.7 初始化顺序:

      在类的内部,变量定义的先后顺序决定了初始化的顺序。静态初始化只有在必要时刻才会进行,此后,初始化对象不会再被初始化。

     

    第六章笔记:第六章笔记:访问权限控制

    6.2 Java访问权限修饰词:

       public:公开,都能访问; private:除了包含该成员的类之外,其他任何类都无法访问 ;protected:继承访问权限,主要体现在:

     1.基类的protected成员是包内可见的,并且对子类可见

     2.若子类与基类不在同一个包中,那么在子类中,子类实例可以访问从基类继承来的protected方法,而不能访问基类实例的protected方法。

     

    第七章:复用类(组合与继承)

    7.1 编译器并不是简单地为每一个引用都创建默认对象,这一点是很有意义的,因为若真要那样做的话,就会在许多情况下增加不必要的负担。如果想初始化这些引用,可以在代码中的下列位置进行:

    1. 在定义对象的地方。这意味着他们总是能够在构造器被调用之前被初始化。

    2. 在类的构造器中。

    3. 就在正要使用这些对象之前,这种方式被称为惰性初始化。在生成对象不值得及不必每次都生成对象的情况下,这种方式可以减少额外的负担。

    4. 使用实例初始化。


    7.2 继承语法:(组合和继承)

       继承是所有OOP语言和Java语言不可缺少的组成部分。当创建一个类时,总是在继承,因此,除非已明确指出要从其他类中继承,否则就是在隐式的从Java的标准根类Object进行继承。

    组合的语法比较平实,但是继承使用的是一种特殊的语法。在继承的过程中需要先声明“新类与旧类相似”。这种声明是通过在类主题的左边花括号之前,回溯斜后面紧随基类名称的关键字extends而实现的,当这么做时,会自动得道基类中的所有域和方法。

    以下部分转载自kk少年的https://www.jianshu.com/p/d345d1bc7e4a

    继承的特点

    • 子类通过关键字extends 实现对父类的继承

    • 子类只可继承来自父类的除私有的属性和方法,对于包访问权限的属性和方法只能被同个包内的子类继承。

    • 构造方法不能被继承。

    • 静态方法和静态变量可以被继承。

    • java中,类之间只可单继承,即一个类只能继承一个父类。

    • 接口亦可继承另一个接口,但是接口可以多继承。

    • 继承的变量和方法可以覆盖。

    • 方法重写不允许降低访问权限。

    • 继承是紧耦合的。

      另外,静态方法不能重写,因为重写指的是根据运行时对象的类型来决定调用哪个方法,而不是编译时的,类静态方法是编译时确定的,即使你在子类中定义了一个和父类一样的静态方法,编译器也不会报错,从多态的角度看,这并不是对静态方法的重写,而是子类自己的方法。

      继承:

      优点:

     (1) 子类自动继承父类接口,在多态时很方便 (2) 创建子类时无需创建父类对象

      缺点:

     (1) 继承破坏封装性

      给父类增加了一个方法A,这时子类与父类之间就可能越来越脱离is-a 举个例子:比如,鸟类有羽毛等属性,这里有一个需求是,定义一个有羽毛的鸡类,采用继承的方法很优雅也很方便,直接一个extends 就可以实现,但是如果有一天,这个鸟类添加了一个飞翔的公有方法,此前继承了鸟类的鸡类会自动继承了这个方法,鸡会飞翔?顶多就是矮距离飞跃。此时给鸡飞的方法就是破坏了鸡的封装性,鸡不应该有此方法。此时的鸡已经和有飞翔行为的鸟类之间不是is-a 关系了。

     (2) 继承是紧耦合:

      继承紧耦合体现在父类变就会影响子类,此时子类如果因此需要修改,重构的难度可能会很高。

     (3) 子类对父类的扩展往往会增加系统结构复杂度

      继承树深度加深,结构越复杂。

     (4) 不支持在运行时指定父类

     (5) 子类不能改变父类的接口

      组合

    什么是组合?给个代码

    public class A{
        public void a1(){}
        public void a2(){}
    }
    ​
    public class B{
        private A a = new A();
        public void a1(){
            a.a1();
        }
        public void a2(){
            a.a2();
        }
    }

    其中B类对A类这种复用的形式就是组合,这个是通过包装和方法转发实现的。

    接下来讲述组合优缺点

    优点

    1. 组合不破坏封装,相对于继承

    2. 组合松耦合,包装类和被包装类彼此独立,不会因为被包装类突然加个方法就使得包装类多了一个方法,包装类视情况包装所需方法。

    3. 支持动态组合,组合的方式在运行时可以根据条件来选择所组合的类。

    4. 包装类可以通过包装改变被包装类的接口,比如被包装类是实现了Set接口的,我可以通过包装,让包装类实现Map接口。

    缺点

    1. 不能实现多态

    2. 无法自动获得被包装类的接口,比如被包装类实现了Set接口,包装类并没有自动获得此接口,需要经过包装,才有可能和他一样的接口。

    何时用继承,何时用组合

      这应该才是我们关心的问题吧。 在以下几种情况使用组合:

    1. 子类只需要继承父类的一部分,继承就没辙了。

    2. 如果只是为了具有父类的一些属性方法,比如汽车具有轮胎和发动引擎,但是如果为此继承这两个类是很不明智的,使用组合更为恰当。

    3. 如果设计的子类是为了复用代码,并不是为了扩展父类,那么最好是选组合的方式,因为父类改变会影响子类。对于只是为了复用而继承的类很不利。

      什么时候使用继承?

    1. 类之间很明显是一种is-a 关系,而不是has-a或者contain-a关系。

    2. 考虑多态时使用继承

    另外:

    组合优于继承是面向对象设计原则之一

     

    7.4 结合使用组成和继承

    同时使用组合和集成式很常见的事。下例就展示了同时使用这两种技术,并配以必要的构造器初始化,来创建更复杂的类

    ``

    package Mypackage;
    import java.io.*;
    import java.sql.SQLOutput;
    import java.util.*;
    ​
    class Plate {
        Plate(int i){
            System.out.println("Plste constructor");
        }
    }
    ​
    class DinnerPlate extends Plate{
        DinnerPlate(int i){
            super(i);
            System.out.println("DinnerPlate  constructor");
        }
    }
    ​
    class Utensil{
        Utensil(int i){
            System.out.println("Utensil constructor");
        }
    }
    ​
    class Spoon extends Utensil{
        Spoon(int i){
            super(i);
            System.out.println("Spoon constructor");
        }
    }
    ​
    class Fork extends Utensil{
        Fork(int i){
            super(i);
            System.out.println("Fork constructor");
        }
    }
    ​
    class Knife extends Utensil{
        Knife(int i){
            super(i);
            System.out.println("Knife constructor");
        }
    }
    ​
    class Custom{
        Custom(int i){
            System.out.println("Custom constructor");
        }
    }
    ​
    public class Study  extends Custom{
        private Spoon sp;
        private Fork frk;
        private Knife kn;
        private DinnerPlate pl;
    ​
         Study(int i){
            super(i+1);
            sp = new Spoon(i+2);
            frk = new Fork(i+3);
            kn = new Knife(i+4);
            pl = new DinnerPlate(i+5);
            System.out.println("PlaceSetting constructor");
        }
    ​
        public static void main(String[] args){
            Study st = new Study(9);
        }
    }
     

    7.8.1 空白final

      Java允许生成空白final,所谓空白final是指被声明为final但又为给定初值的域。无论什么情况,编译器都确保空白final在使用前必须被初始化。但是,空白final在关键字final的使用上提供了更大的灵活性,为此,一个类中的final域就可以做到根据对象而有所不同,却又保持恒定不变的特性。

    final和private关键字: 类中所有的private方法都隐式的指定是final的,可以对private方法添加final修饰词,但这并不能给方法增加任何额外的意义。

    总结:

      继承和组合都能从现有类型生成新类型。组成一般是将现有类型作为新类型底层实现的一部分来加以复用,耳继承复用的是接口。

    在使用继承时,由于导出类具有基类接口,因此它可以向上转型直基类,这对多态来说至关重要。

    尽管面向对象编程对继承极力强调,但在开始一个设计时,一般应优先选择使用组合(或者代理),旨在确实必要时才使用继承。应为组合更具灵活性。此外,通过对成员类型使用继承技术的添加技巧,可以在运行时改变那些成员对象的类型和行为。因此,可以在运行时改变组合而成的对象的行为。

     

    第八章:多态

    8.2.5:

       只有普通的方法是可以调动多态的,如果某个方法是静态的,它的行为就不具有多态性。

    8.3.1:构造器调用的顺序:

     1)调用基类构造器。这个步骤会不断的反复递归下去,首先是构造这种层次结构的根,然后是下一层导出类,等等,直到最底层的导出类。

     2)按声明顺序调用成员的初始化方法。

     3)调用导出类构造器的主体。

     

    第九章笔记:接口

    9.2:接口

    abstract关键字允许人们在类中创建一个或多个没有任何定义的方法——提供了接口部分,但是没有提供任何相应的具体实现,这些实现是由此类的继承者创建的。interface这个关键字产生一个完全抽象的类,它根本就没有提供任何具体实现。它允许创建者确定方法名、参数列表和返回类型,但是没有任何方法体。

     

    第十章笔记:内部类

    10.2 链接到外部类

    当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有元素的访问权。

    10.3 使用.this和.new

    有时你可能想要告知某些其他对象,去创建起某个内部类的对象。要实现此目的,你必须在new表达式中提供对其他外部类对象的引用,这是需要使用.new语法,就像下面这样:

    public class DotNew{
        public class Inner{}
        public static void main(String[] args){
            DotNew dn = new DotNew();
            DotNew.Inner dni = dn.new Inner();
        }
    }
     

    10.6 匿名内部类

    public class Parcel7{
        public Contents contents(){
            return new Contents(){
                private int i = 11;
                public int value(){ return i; }
            };
        }
        public static void main(String[] args){
            Parcel7 p = new Parcel7();
            Contents c = p.contents();
        }
    }
     

    contents()方法将返回值的生成与表示这个返回值的类的定义结合在一起!另外,这个类是匿名的。这种奇怪的语法指的是:“创建一个继承自Contents的匿名类对象”。通过new表达式返回的引用被自动向上转型为对Contents的应用。


    import static net.mindview.util.Print.*;
    ​
    abstract class Base{
        public Base(int i){
            print("Base constructor,i = " + i);
        }
        public abstract void f();
    }
    ​
    public class AnonymousConstructor{
        public static Base getBase(int i){
            return new Base(i){
                { print("Inside instance initializer"); }
                public void f(){
                    print("In anonymous f()");
                }
            };
        }
        
        public static void main(String args){
            Base base = getBase(47);
            base.f();
        }
    }
    /*output
    *Base constructor , i = 47
    *Inside instance initializer
    *In anonymous f()
    */
     

    在此例中,不要求变量i一定是final的。因为i被传递给匿名类的基类构造器,它并不会在匿名内部类内部被直接使用。

    如果在匿名类内部使用的,方法签名中的参数必须是final的,如destination(final String dest, final float price){}

    10.7 嵌套类

    如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。这通常称为嵌套类。想要理解static应用于内部类时的含义,就必须记住,普通的内部类对象隐式的保存了一个引用,只想创建它的外围类对象。然而,当内部类是static时,就不是这样了。嵌套意味着:

    1)要创建嵌套类的对象,并不需要其外围类的对象。

    2)不能从嵌套类的对象中访问非静态的外围类对象。

    嵌套类与普通的内部类还有一个区别。普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。但是嵌套类可以包含所有这些东西。

    10.7.1 接口内部的类

    正常情况下,不能再接口内部防止任何代码,但嵌套类可以作为接口的一部分。你放到接口中的任何类都自动的是public和static的,因为类是static的,只是将嵌套类至于接口的命名空间内,这并不违反接口的原则。你甚至可以在内部类中实现其外围接口,就像如下:

    public interface ClassInterface{
        void howdy();
        class Test implments ClassInterface{
            public void howdy(){
                System.out.println("Howdy!");
            }
            public static void main(Stringp[] args){
                new Test().howdy();
            }
        }
    }
     

    10.7.2 从多层嵌套类中访问外部类的成员

    一个内部类被嵌套多少层并不重要——它能透明的访问它所嵌入的外围类的所有成员。

    10.8 为什么需要内部类

    一般来说,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。所以可以认为内部类提供了某种进入外围类的窗口。

    内部类必须回答的一个问题是:如果只是需要一个对接口的引用,为什么不通过外围类实现那个接口呢?答案是:“如果这能满足需求,那么就这么做。”

    那么内部类实现一个接口与外围类实现这个接口又有什么区别?答案是“后者不是总能享用到接口带来的方便,有时需要用到接口的实现。”所以使用内部类最吸引人的原因是:每个内部类都能独立的继承一个(接口的)实现,所以无论外围类是否已经继承了(接口的)实现,对于内部类都没有影响。

    如果拥有的是抽象的类或具体的类,而不是接口,那只能使用内部类才能实现多重继承。

    10.10 内部类可以覆盖吗?

    “覆盖”内部类就好像它是外围类的一个方法,其实不起什么作用。

     



  • 相关阅读:
    Ext.widgetsform(上)BasicForm/Field/Checkbox/Radio/HtmlEditor/TextField
    EXT核心API详解(二)Array/Date/Function/Number/String
    Think of Ext2.0
    EXT核心API详解(七)Ext.KeyNav/KeyMap/JSON/Format/DelayedTask/TaskRunner/TextMetrics/XTemplate
    Ext架构分析(2)理解Ext.util.Observable
    Ext.dataStore
    Ext架构分析(1)理解Ext.util.Event
    Spket Eclipse插件使用教程
    Ext.widgetsform(下)ComboBox,TimeField,DateField,TriggerField,TextArea,NumberField
    Ext.menu.Menu
  • 原文地址:https://www.cnblogs.com/wxx23-IOU/p/14045481.html
Copyright © 2011-2022 走看看