zoukankan      html  css  js  c++  java
  • Java Knowledge series 3

    JVM & Bytecode

    Abstract & Object

    1. Object in Java
    • (1) 所有东西都是对象object。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作self-operation(this pointer is always as parameter pssing to function called on object)。理论上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。
    • (2) 程序是一大堆对象的组合combination;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那个对象“发送一条消息”。更具体地讲,可将消息想象为一个调用请求invocation request,它调用的是从属于目标对象的一个子例程routine或函数。
    • (3) 每个对象都有自己的存储空间memory,可容纳contain, accommodate其他对象。或者说,通过封装现有对象,可制作出新型对象。所以,尽管对象的概念非常简单,但在程序中却可达到任意高的复杂程度complexity。Everthing is object in Java, except for built-in type.
    • (4) 每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实例”。其中,“类”(Class)是“类型”(Type)的同义词synonym。一个类最重要的特征就是“能将什么消息发给它?”。Interface-oriented, near to principle of Design Pattern.
    • (5) 同一类所有对象都能接收相同的消息。这实际是别有含义的一种说法,大家不久便能理解。由于类型为“圆”(Circle)的一个对象也属于类型为“形状”(Shape)的一个对象,所以一个圆完全能接收形状消息(Draw)。这意味着可让程序代码统一指挥“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包括“圆”。这一特性称为对象的“可替换性”replace, substitution,是OOP最重要的概念之一。
    1.  “接口”(Interface)规定了可对一个特定的对象发出哪些请求。然而,必须在某个地方存在着一些代码,以便满足这些请求。这些代码与那些隐藏起来的数据便叫作“隐藏的实现”。站在程式化程序编写(Procedural Programming)的角度,整个问题并不显得复杂。一种类型含有与每种可能的请求关联起来的函数。一旦向对象发出一个特定的请求,就会调用那个函数。我们通常将这个过程总结为向对象“发送一条消息”(提出一个请求)。对象的职责就是决定如何对这条消息作出反应(执行相应的代码)。Same as the pure abstraction class.
    2. 若接口与实现方法早已隔离开,并分别受到保护,就可放心做到这一点,只要求用户重新链接一下即可。Java采用三个显式(明确)关键字以及一个隐式(暗示)关键字来设置类边界:public,private,protected以及暗示性的friendly。若未明确指定其他关键字,则默认为后者。Friendly is used in default.
    3. “public”(公共)意味着后续的定义任何人均可使用。而在另一方面,“private”(私有)意味着除您自己、类型的创建者以及那个类型的内部函数成员,其他任何人都不能访问后续的定义信息。“friendly”(友好的)涉及“包装”或“封装”(Package)的概念——即Java用来构建库的方法。若某样东西是“友好的”,意味着它只能在这个包装的范围内使用(所以这一访问级别有时也叫作“包装访问”)。“protected”(受保护的)与“private”相似,只是一个继承的类可访问受保护的成员,但不能访问私有成员。
    4. 继承inheritence(is-a):重新使用接口. 在继承过程中,若原始类(正式名称叫作基础类、超类或父类)发生了变化,修改过的“克隆”类(正式名称叫作继承类或者子类)也会反映出这种变化。在Java语言中,继承是通过extends关键字实现的使用继承时,相当于创建了一个新类。这个新类不仅包含了现有类型的所有成员(尽管private成员被隐藏hide起来,且不能访问),但更重要的是,它复制了基础类的接口。也就是说,可向基础类的对象发送的所有消息亦可原样发给衍生类的对象。根据可以发送的消息,我们能知道类的类型。这意味着衍生类derived class具有与基础类相同的类型!为真正理解面向对象程序设计的含义,首先必须认识到这种类型的等价关系equivalence。
    5. 第一种做法十分简单:为衍生类添加新函数(功能).尽管extends关键字暗示imply着我们要为接口“扩展”extend新功能,但实情并非肯定如此。为区分distinguish我们的新类,第二个办法是改变基础类一个现有函数的行为。我们将其称作“改善better, improve”那个函数. 为改善一个函数,只需为衍生类的函数建立一个新定义即可(same as override in C++, but there is a little difference)。我们的目标是:“尽管使用的函数接口未变,但它的新版本具有不同的表现”。Redefine the function in the based class.
    6. A kind of relation of equivalence and similarity between base class and derived class.
    7. 将一条消息发给对象时,如果并不知道对方的具体类型是什么,但采取的行动同样是正确的,这种情况就叫作“多形性”(Polymorphism)。对面向对象的程序设计语言来说,它们用以实现多形性的方法叫作“动态绑定” dynamic binding。编译器和运行期系统会负责对所有细节的控制. 在C++中,这个关键字是virtual。在Java中,我们则完全不必记住添加一个关键字,因为函数的动态绑定是自动进行的 all functions is dynamically bound to the real object in JVM in run-time. All functions defined in Java are bond dynamically or deduced in run-time.
    8. abstract关键字描述一个尚未实现的方法——作为一个“根”使用,指出:“这是适用于从这个类继承的所有类型的一个接口函数,但目前尚没有对它进行任何形式的实现。”抽象方法也许只能在一个抽象类里创建。继承了一个类后,那个方法就必须实现,否则继承的类也会变成“抽象”类。通过创建一个抽象方法,我们可以将一个方法置入接口中,不必再为那个方法提供可能毫无意义meaningless的主体代码。Abstract class can not be used to create a object. Abstract method must be given the real implementation in derived class.
    9. interface(接口pure abstract class)关键字将抽象类的概念更延伸了extend, prolong一步,它完全禁止了所有的函数定义。“接口”是一种相当有效valid和常用的useful工具。另外如果自己愿意,亦可将多个接口都合并到一起(不能从多个普通class或abstract class中继承)。
    10. 从技术角度说,OOP(面向对象程序设计)只是涉及抽象的数据类型、继承以及多形性. Abstraction of data, inheritance, polymorphism.
    11. OOP = Encapsulation + Inheritance + Polymorphism (some Late binding)
    12. Component-Oriented Programming = Polymorphism + (Really) late binding + (Real, Enforced/ Imperative) Encapsulation + Interface Inheritance + Binary Reuse
    13. OOD, OOP are used for constantly changing requirement.
    14. COM is used for middle-ware development.
    15. SOA = Service-Oriented Architecture over Web to implement Web Application
    16. Container / aggregation 设计优良的OOP语言都配套提供了一系列集合collection。在C++中,它们是以“标准模板库”(STL)的形式提供的。
    17. 在Java中(与其他几乎所有OOP语言一样),对这个问题的答案都是肯定的,而且这个终级基础类的名字很简单,就是一个“Object”。这种“单根结构”single root具有许多方面的优点。
    18. Single Root + Multi-Interface implementation in Java system.
    19. 由于运行期的类型信息RTTI肯定存在于所有对象中,所以永远不会遇到判断不出一个对象的类型的情况。这对系统级的操作来说显得特别重要,比如违例控制;而且也能在程序设计时获得更大的灵活性。
    20. 为了使这些集合能够重复使用,或者“再生”,Java提供了一种通用类型,以前曾把它叫作“Object”。单根结构意味着、所有东西归根结底都是一个对象”!所以容纳了Object的一个集合实际可以容纳任何东西。The type of element stored in container just is Object. It is different from C++. This will facilitate user to use and manage container.
    21. 为使用这样的一个集合,只需添加指向它的对象句柄handle(In java, all variables are object handle, no pointer or reference in C++)即可,以后可以通过句柄重新使用对象。但由于集合只能容纳Object,所以在我们向集合里添加对象句柄时,它会上溯造型成Object,这样便丢失了它的身份或者标识信息type ID。再次使用它的时候,会得到一个Object句柄,而非指向我们早先置入的那个类型的句柄。Up cast; down cast.if (newSource instanceof Component) {comp = (Component)newSource;}  但必须注意一个问题:共享资源!如果有多个线程同时运行,而且它们试图访问相同的资源,就会遇到一个问题。Thread model is provided by OS.
    22. Java也提供了有限的资源锁定方案。它能锁定任何对象占用的内存(内存实际是多种共享资源的一种),所以同一时间只能有一个线程使用特定的内存空间。为达到这个目的,需要使用synchronized关键字。其他类型的资源必须由程序员明确锁定,这通常要求程序员创建一个对象,用它代表一把锁,所有线程在访问那个资源时都必须检查这把锁。{…; synchronized (this) {source = newSource; …} } // as part of function    public synchronized void setDropTarget(DropTarget dt){…} // as keyword for definition of function
    23. 尽管这一现象表面上非常合理,但深入追究就会发现,假如在程序停止运行以后,对象也能继续存在,并能保留它的全部信息,那么在某些情况下将是一件非常有价值的事情。下次启动程序时,对象仍然在那里,里面保留的信息仍然是程序上一次运行时的那些信息。当然,可以将信息写入一个文件或者数据库,从而达到相同的效果。但尽管可将所有东西都看作一个对象,如果能将对象声明成“永久性” (permanent), transient(temporary)
    24. though/ in spite of/ despite/whereas尽管以C++为基础,但Java是一种更纯粹的面向对象程序设计语言. 但要注意Note that/ Notice that,尽管将一切都“看作”regard对象,但操纵的标识符实际是指向一个对象的“句柄”(Handle. Same as/similar to pointer or reference in C++).
    25. 一个String句柄:String s;但这里创建的只是句柄,并不是对象。若此时向s发送一条消息,就会获得一个错误(运行期).Just a handle not object which has to be allocated memory. 所有对象都必须创建. Explicitly create with new operator.
    26. 六个地方都可以保存数据:
      • 1 寄存器register。这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部 only used in CPU, hardware layer, or JVM layer。
      • 2 堆栈stack used in compiling time。驻留于常规RAM(随机访问存储器)区域,但可通过它的“栈指针”获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移move up,则会释放那些内存。但Java对象并不放到其中。This constraint places limits on the flexibility of your programs, so while some Java storage exists on the stack—in particular, object references—Java objects themselves are not placed on the stack. 
      • 3 堆heap。一种常规用途的内存池(也在RAM区域),其中保存了Java对象。和堆栈不同,“内存堆”或“堆”(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。4静态存储static storage。这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间。You can use the static keyword to specify that a particular element of an object is static, but Java objects themselves are never placed in static storage. 5常数存储constant(static final int i=0)。常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格地保护,所以可考虑将它们置入只读存储器(ROM)。6非RAM存储。若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固定对象fixed”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于固定对象,对象保存在磁盘中。
    27. 可将它们想象成“基本”、“主要”或者“主”(Primitive)类型, build-in type; 由于用new创建对象(特别是小的、简单的变量)并不是非常有效,因为new将对象置于“堆”里。对于这些类型,Java采纳了与C和C++相同的方法。也就是说,不是用new创建变量,而是创建一个并非句柄的“自动”变量。这个变量容纳了具体的值,并置于堆栈中,能够更高效地存取。Build-in/Primitive type is allocated in stack not heap.
    28. The reason for the special treatment is that to create an object with new—especially a small, simple variable—isn’t very efficient, because new operation places objects on the heap. For these types Java falls back on the approach taken by C and C++. That is, instead of creating the variable by using new, an “automatic” variable is created that is not a reference. The variable holds the value, and it’s placed on the stack, so it’s much more efficient.
    29. The “wrapper” classes for the primitive data types allow you to make a nonprimitive object on the heap to represent that primitive type. Character C = new Character(c);
    30. When you create an array of objects, you are really creating an array of references, and each of those references is automatically initialized to a special value with its own keyword: null. When Java sees null, it recognizes that the reference in question isn’t pointing to an object. You must assign an object to each reference before you use it, and if you try to use a reference that’s still null, the problem will be reported at run time. Thus, typical array errors are prevented in Java.
    31. As in any situation in Java where you seem to be handing objects around, you are actually passing references.
    32. 构建器constructor的名字与类名相同。这样一来,可保证象这样的一个方法会在初始化期间自动调用。
    33. You never need to destroy an object in Java. All objects are allocated on heap. In C++, some objects are allocated on the stack, so they have their scoping life.
    34. 构建器属于一种较特殊peculiar/special的方法类型,因为它没有返回值。这与void返回值存在着明显的apparent/evident区别。对于void返回值,尽管方法本身不会自动返回什么,但仍然可以让它返回另一些东西。构建器则不同,它不仅什么也不会自动返回,而且根本不能有任何选择。若存在一个返回值,而且假设suppose/supposing我们可以自行选择返回内容,那么编译器多少要知道如何对那个返回值作什么样的处理。
    35. 在Java里,另一项因素强迫force; enforce; compel; impose; coerce;imperative 方法名出现过载overload情况:构建器。由于构建器的名字由类名决定,所以只能有一个构建器名称.
    36. 而且别人如何识别并理解代码呢?由于存在这一类的问题,所以不能根据返回值类型来区分过载的方法。For sometimes the return value is neglected or noted.
    37. 默认构建器是没有自变量的。它们的作用是创建一个“空对象”。若创建一个没有构建器的类,则编译程序会帮我们自动创建一个默认构建器。Default constructor;
    38. 针对这一目的有个专用的especial关键字:this。this关键字(注意只能在方法内部使用)可为已调用了其方法的那个对象生成相应的句柄。可象对待其他任何对象句柄一样对待这个句柄。但要注意,假若准备从自己某个类的另一个方法内部调用一个类方法,就不必使用this。只需简单地调用那个方法即可。
    39. this关键字只能用于那些特殊的类——需明确使用当前对象的句柄。例如,假若您希望将句柄返回给当前对象,那么它经常在return语句中使用。
    40. 若为一个类写了多个构建器,那么经常都需要在一个构建器里调用另一个构建器,以避免写重复的代码。可用this关键字做到这一点。
    41. 它意味means着一个特定的方法没有this。我们不可从一个static方法内部发出对non-static方法的调用(注释②notation, remark, annotate,comment),尽管反过来说是可以的。而且在没有任何对象的前提下,我们可针对类本身发出对一个static方法的调用。事实上,那正是static方法最基本的意义。它就好象我们创建一个全局函数的等价物(在C语言中)。除了全局函数不允许在Java中使用以外,若将一个static方法置入一个类的内部,它就可以访问其他static方法以及static字段。There is not <this> parameter in static function, so the non-static variable can’t be called in static function.
    42. The other is if you need a method that isn’t associated with any particular object of this class. That is, you need a method that you can call even if no objects are created. You can achieve both of these effects with the static keyword.
    43. When you say something is static, it means that data or method is not tied to any particular object instance of that class. So even if you’ve never created an object of that class you can call a static method or access a piece of static data. With ordinary, non-static data and methods, you must create an object and use that object to access the data or method, since non-static data and methods must know the particular object they are working with. Of course, since static methods don’t need any objects to be created before they are used, they cannot directly access non-static members or methods by simply calling those other members without referring to a named object (since non-static members and methods must be tied to a particular object).
    44. Static methods, which you’ll learn about soon, can be called for the class, without an object.
    45. 垃圾收集器garbage collector只知道释放那些由new分配的内存,所以不知道如何释放对象的“特殊”内存。为解决这个问题,Java提供了一个名为finalize()的方法,可为我们的类定义它。在理想情况下,它的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存。所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除weed out; clean out; eliminate或清扫rip up/ sweep工作。
    46. 相反conversely,to the contrary; in opposite direction; Java不允许我们创建本地(局部)对象——无论如何at any rate; in all events; whatever happens 都要使用new。但在Java中,没有“delete”命令来释放对象,因为垃圾收集器会帮助我们自动释放存储空间。
    47. 在一个类里,初始化的顺序是由变量在类内的定义顺序决定的。即使变量定义大量遍布于方法定义的中间,那些变量仍会在调用任何方法之前得到初始化——甚至在构建器调用之前。In order of which the member is declared.
    48. static初始化只有在必要的时候才会进行。如果不创建一个Table对象,而且永远都不引用Table.b1或Table.b2,那么static Bowl b1和b2永远都不会创建。然而,只有在创建了第一个Table对象之后(或者发生了第一次static访问),它们才会创建。在那以后,static对象不会重新初始化。初始化的顺序 order of initialization是首先static(如果它们尚未由前一次对象创建过程初始化),接着是非static对象。大家可从输出结果中找到相应的证据。
    49. Java does not need a sizeof( ) operator for this purpose, because all the data types are the same size on all machines. You do not need to think about portability on this level—it is designed into the language.
    50. 在这里有必要总结summarize一下对象的创建过程。请考虑一个名为Dog的类:
      • (1) 类型为Dog的一个对象首次创建时,或者Dog类的static方法/static字段首次访问时,Java解释器必须找到Dog.class(在事先设好的类路径里搜索)。
      • (2) 找到Dog.class后(它会创建一个Class对象,这将在后面学到),它的所有static初始化模块都会运行。因此,static初始化仅发生一次——在Class对象首次载入的时候。
      • (3) 创建一个new Dog()时,Dog对象的构建进程首先会在内存堆(Heap)里为一个Dog对象分配足够多的存储空间。
      • (4) 这种存储空间会清为零,将Dog中的所有built-in type基本类型设为它们的默认值(零用于数字,以及boolean和char的等价设定)。
      • (5) 进行字段定义时发生的所有初始化都会执行。
      • (6) 执行构建器。
    51. 明确definitely 进行的静态初始化Java允许我们将其他static初始化工作划分到类内一个特殊的“static构建从句”(有时也叫作“静态块”)里。它看起来象下面这个样子:class Spoon {  static int i;  static {    i = 47;  } }
    52. 在C中初始化数组极易出错,而且相当麻烦。C++通过“集合初始化”使其更安全(注释⑥)。Java则没有象C++那样的“集合”概念,因为Java中的所有东西都是对象。但它确实有自己的数组,通过数组初始化来提供支持。数组代表一系列对象或者基本数据类型,所有相同的类型都封装到一起——采用一个统一的标识符名称。数组的定义和使用是通过方括号索引运算符进行的([])。为定义一个数组,只需在类型名后简单地跟随一对空方括号即可:int[] al;
    53. “进行面向对象的设计时,一项基本的essential考虑是:如何将发生变化的东西与保持不变的东西分隔开。” Separate changing thing from unchanging thing.
    54. 我们用import关键字导入一个完整的库时,就会获得“包”(Package). package mypackage;那么package语句必须作为文件的第一个非注释语句出现。该语句的作用是指出这个编译单元属于名为mypackage的一个库的一部分。或者换句话说,它表明这个编译单元内的public类名位于mypackage这个名字的下面。如果其他人想使用这个名字,要么指出完整的名字,要么与mypackage联合使用import关键字(使用前面给出的选项)
    55. Java访问指示符poublic,protected以及private都置于它们的最前面——无论它们是一个数据成员,还是一个方法。每个访问指示符都只控制着对那个特定定义的访问。这与C++存在着显著不同。在C++中,访问指示符控制着它后面的所有定义,直到又一个访问指示符加入为止。
    56. 默认的访问没有关键字,但它通常称为“友好”(Friendly)访问。这意味着当前包内的其他所有类都能访问“友好的”成员,但对包外的所有类来说,这些成员却是“私有”(Private)的,外界不得访问。由于一个编译单元(一个文件)只能从属于单个包,所以单个编译单元内的所有类相互间都是自动“友好”的。因此,我们也说友好元素拥有“包访问”权限。
    57. 友好访问允许我们将相关的类都组合到一个包里,使它们相互间方便地进行沟通。
    58. 为获得对一个访问权限,唯一的方法就是:(1) 使成员成为“public”(公共的)。这样所有人从任何地方都可以访问它。(2) 变成一个“友好”成员,方法是舍弃所有访问指示符,并将其类置于相同的包内。这样一来,其他同包的类就可以访问成员.(3) 正如以后引入“继承”概念后大家会知道的那样,一个继承的类既可以访问一个protected成员,也可以访问一个public成员(但不可访问private成员)。只有在两个类位于相同的包内时,它才可以访问友好成员。但现在不必关心这方面的问题。(4) 提供“访问器/变化器”方法(亦称为“获取/设置”方法),以便读取和修改值。这是OOP环境中最正规的一种方法,也是Java Beans的基础/. Access right is decided in compile time.
    59. Java把象这样的文件看作那个目录“默认包”的一部分,所以它们对于目录内的其他文件来说是“友好”的。
    60. 这个原因直接导致了第二个原因:我们需要将接口同实施细节分离开(Segregate interface from implementation)。若结构在一系列程序中使用,但用户除了将消息发给public接口之外,不能做其他任何事情,我们就可以改变不属于public的所有东西(如“友好的”、protected以及private),同时不要求用户对他们的代码作任何修改。
    61. 将public成员置于最开头,后面跟随protected、友好以及private成员
    62. (1) 每个编译单元(文件)都只能有一个public类。每个编译单元有一个公共接口的概念是由那个公共类表达出来的。根据自己的需要,它可拥有任意多个提供支撑的“友好”类。但若在一个编译单元里使用了多个public类,编译器就会向我们提示一条出错消息。(2) public类的名字必须与包含了编译单元的那个文件的名字完全相符,甚至包括它的大小写形式。所以对于Widget来说,文件的名字必须是Widget.java,而不应是widget.java或者WIDGET.java。同样地,如果出现不符,就会报告一个编译期错误。(3) 可能(但并常见)有一个编译单元根本没有任何公共类。此时,可按自己的意愿任意指定文件名。
    63. 第一个最简单:在新类里简单地创建原有类的对象。我们把这种方法叫作“合成composition”(has-a relationship),因为新类由现有类的对象合并而成。我们只是简单地重复利用代码的功能,而不是采用它的形式。第二种方法则显得稍微有些技巧。它创建一个新类,将其作为现有类的一个“类型”。我们可以原样采取现有类的形式,并在其中加入新代码,同时不会对现有的类产生影响。这种魔术般的行为叫作“继承”(Inheritance),涉及的大多数工作都是由编译器完成的。对于面向对象的程序设计,“继承”是最重要的基础概念之一
    64. 如希望句柄得到初始化,可在下面这些地方进行:initialization(1) 在对象定义的时候。这意味着它们在构建器调用之前肯定能得到初始化。(2) 在那个类的构建器中。(3) 紧靠在要求实际使用那个对象之前。这样做可减少不必要的开销——假如对象并不需要创建的话。
    65. 但为了进行继承,必须采用一种全然不同的形式。需要继承的时候,我们会说:“这个新类和那个旧类差不多almost /very close。”为了在代码里表面这一观念,需要给出类名。但在类主体的起始花括号之前,需要放置一个关键字extends,在后面跟随“基础类”的名字。若采取这种做法,就可自动获得基础类的所有数据成员以及方法。
    66. 倘若省略omit/neglect/miss所有访问指示符,则成员默认为“友好的” friend by default。这样一来,就只允许对包成员进行访问。在这个包内,任何人都可使用那些没有访问指示符的方法。
    67. 所以在计划继承的时候,一个比较好的规则是将所有字段都设为private,并将所有方法都设为public(protected成员也允许衍生出来的类访问它;以后还会深入探讨这一问题)。当然,在一些特殊的场合,我们仍然必须作出一些调整coordinate /adjust/ regulate/adapt,但这并不是一个好的做法。
    68. 为解决这个问题,Java提供了一个super关键字,它引用当前类已从中继承的一个“超类”(Superclass)。所以表达式super.scrub()调用的是方法scrub()的基础类版本。
    69. 基础类子对象应该正确地初始化,而且只有一种方法能保证这一点:在构建器中执行初始化,通过调用基础类构建器,后者有足够的能力和权限来执行对基础类的初始化。在衍生类derived calss的构建器中,Java会自动插入对基础类构建器的调用。
    70. 即使没有为Cartoon()创建一个构建器,编译器也会为我们自动合成一个默认构建器,并发出对基础类构建器的调用。如果类没有默认的自变量,或者想调用含有一个自变量的某个基础类构建器,必须明确explicitly地编写对基础类的调用代码。这是用super关键字以及适当的自变量列表实现的.
    71. 正如刚才指出的那样,编译器会强迫我们在衍生类构建器的主体中首先设置对基础类构建器的调用。这意味着在它之前不能出现任何东西。
    72. 许多时候都要求将合成与继承两种技术结合起来使用。
    73. 其中,try关键字指出后面跟随的块(由花括号定界)是一个“警戒区”。也就是说,它会受到特别的待遇。其中一种待遇就是:该警戒区后面跟随的finally从句的代码肯定会得以执行——不管try块到底存不存在(通过违例exception控制技术,try块可有多种不寻常的应用)。在这里,finally从句的意思是“总是为x调用cleanup(),无论会发生什么事情” whatever happened.。
    74. 只有C++程序员可能才会惊讶于名字的隐藏,因为它的工作原理与在C++里是完全不同的。如果Java基础类有一个方法名被“过载”使用多次,在衍生类里对那个方法名的重新定义就不会隐藏任何基础类的版本。所以无论方法在这一级还是在一个基础类中定义,过载overloaded都会生效. Different from overriding overloaded functions in C++.
    75. Everything is an Object in Java.
    76. Although Java is based on C++, Java is more of a pure object-oriented language.
    77. The reason C++ is hybrid is to support backward compatibility with the C language.
    78. Are you manipulating the object directly, or are you dealing with some kind of indirect representation (a pointer in C or C++) that must be treated with a special syntax?
    79. All this is simplified in Java. You treat everything as an object, using a single consistent syntax. Although you treat everything as an object, the identifier you manipulate is actually a “reference” to an object. String s; //Just create a String reference, no an object. You can’t send a message to s at this point with an error at run time. Because it is not actually attached to anything.String s = "asdf" or s = new String; //A safer practice, then, is always to initialize a reference when you create it
    80. Each object keeps its own storage for its fields; the fields are not shared among objects, but the methods are shared among objects by passing an this parameter to it implicitly.
    81. Java also adopted the constructor, and in addition has a garbage collector that automatically releases memory resources when they’re no longer being used.
    82. The name of the constructor is the same as the name of the class. It makes sense that such a method will be called automatically on initialization.
    83. Constructor arguments provide you with a way to provide parameters for the initialization of an object.
    84. The constructor is an unusual type of method because it has no return value. This is distinctly different from a void return value, in which the method returns nothing but you still have the option to make it return something else. Constructors return nothing and you don’t have an option (the new expression does return a reference to the newly-created object, but the constructor itself has no return value). If there were a return value, and if you could select your own, the compiler would somehow need to know what to do with that return value.
    85. Often, the same word expresses a number of different meanings—it’s overloaded. This is useful, especially when it comes to trivial differences.
    86. And although method overloading is a must for constructors, it’s a general convenience and can be used with any method. Actually, these methods will be modified to the different by adding some post-symbol (like argument type).
    87. The default constructor, also called (a.k.a. = also known as) the no-arg constructor.
    88. There’s a simple rule: each overloaded method must take a unique list of argument types.
    89. Overloading with primitives: A primitive can be automatically promoted from a smaller type to a larger one, and this can be slightly confusing in combination with overloading.
    90. Overloading on return values: Ignore the return type.
    91. If you create a class that has no constructors, the compiler will automatically create a default constructor for you.creates a new object and calls the default constructor, even though one was not explicitly defined. Without it, we would have no method to call to build our object. However, if you define any constructors (with or without arguments), the compiler will not synthesize one for you.
    92. To allow you to write the code in a convenient object-oriented syntax in which you “send a message to an object,” the compiler does some undercover/backdoor/background work for you.
    93. There’s a secret first argument passed to the method f( ), and that argument is the reference to the object that’s being manipulated.
    94. CUserClass.Method( oUserObject, 1 ){ oUserObject.variable1 =….; oUserObject.variable2 = …;};
    95. Suppose you’re inside a method and you’d like to get the reference to the current object. Since that reference is passed secretly by the compiler, there’s no identifier for it. However, for this purpose there’s a keyword: this. The this keyword—which can be used only inside a method—produces the reference to the object the method has been called for. You can treat this reference just like any other object reference. Keep in mind that if you’re calling a method of your class from within another method of your class, you don’t need to use this. You simply call the method. The current this reference is automatically used for the other method.
    96. With the this keyword in mind, you can more fully understand what it means to make a method static. It means that there is no this for that particular static method. You cannot call non-static methods from inside static methods (although the reverse is possible), and you can call a static method for the class itself, without any object. In fact, that’s primarily what a static method is for.
    97. However, global functions are not permitted in Java, and putting the static method inside a class allows it access to other static methods and to static fields.
    98. Some people argue that static methods are not object-oriented, since they do have the semantics of a global function; with a static method, you don’t send a message to an object, since there’s no this. You have only one way to call static method through Class. This is probably a fair argument, and if you find yourself using a lot of static methods, you should probably rethink your strategy. However, statics are pragmatic / practical, and there are times when you genuinely need them, so whether or not they are “proper OOP” should be left to the theoreticians. Indeed, even Smalltalk has the equivalent in its “class methods.”
    99. Java goes out of its way to guarantee that variables are properly initialized before they are used.
    100. You’ll see later that when you define an object reference inside a class without initializing it to a new object, that reference is given a special value of null (which is a Java keyword). You’ll get a run-time error called an exception.
    101. Within a class, the order of initialization is determined by the order that the variables are defined within the class. The variable definitions may be scattered throughout and in between method definitions, but the variables are initialized before any methods can be called—even the constructor.
    102. Class is loaded if needed: allocate memory on heap -> initial static variable and block if not being initialized by a previous object creation -> initial non-static variable in the order of these definition with given value or default value-> invoke constructor
    103. When the data is static, the same thing happens; if it’s a primitive and you don’t initialize it, it gets the standard primitive initial values. If it’s a reference to an object, it’s null unless you create a new object and attach your reference to it.
    104. You can see that the static initialization occurs only if it’s necessary. The order of initialization is statics first, if they haven’t already been initialized by a previous object creation, and then the non-static objects.
    105. It appears to be a method, but it’s just the static keyword followed by a block of code. This code, like other static initializations, is executed only once: the first time you make an object of that class or the first time you access a static member of that class (even if you never make an object of that class).
    106. Explicit static initialization: Java allows you to group other static initializations inside a special “static clause” (sometimes called a static block) in a class. Static variable & Static block
    107. Joshua Bloch goes further in his section titled “avoid finalizers”: “Finalizers are unpredictable, often dangerous, and generally unnecessary.”
    108. In contrast, C++ has the constructor initializer list that causes initialization to occur before entering the constructor body, and is enforced for objects.
    109. Java allows you to easily create multi-dimensional arrays:
    110. The second form provides a convenient syntax to create and call methods that can produce the same effect as C’s variable argument lists (known as “varargs” in C). These can include unknown quantities of arguments as well as unknown types. Since all classes are ultimately inherited from the common root class Object (a subject you will learn more about as this book progresses), you can create a method that takes an array of Object
    111. All arrays have an intrinsic/inherent member (whether they’re arrays of objects or arrays of primitives) that you can query—but not change—to tell you how many elements there are in the array. This member is length. Since arrays in Java, like C and C++, start counting from element zero, the largest element you can index is length - 1.
  • 相关阅读:
    Java转大数据开发全套视频资料
    Java注解Annotation的用法
    SpringBoot集成CAS单点登录,SSO单点登录,CAS单点登录(视频资料分享篇)
    零基础如何学习Java和web前端
    如何看待B站疑似源码泄漏的问题?
    如何自学编程,零基础适合学习Java或者Web前端吗,非科班的能学java吗?
    Spring中常用的注解,你知道几个呢?
    学习分布式系统需要怎样的知识?
    程序员如何学习互联网前言技术呢,我给你10个建议
    回看面试中的这些坑,你踩过几个?
  • 原文地址:https://www.cnblogs.com/iiiDragon/p/3237860.html
Copyright © 2011-2022 走看看