Java语法(一)基本语法(think in java 笔记)

 

static方法和final方法都是前期绑定的,不存在多态概念。

是否需要从新类上溯造型回基础类(是否要用到多态)。若必须上溯,就需要继承;否则用组合。

                继承和抽象和多态联系更紧密。,

前言:

Java为我们提供了一种表达思想的方式。不可将Java简单想象成一系列特性的集合;如孤立地看,有些特性是没有任何意义的。只有在考虑“设计”、随着问题变得愈大和愈复杂,而非考虑简单的编码时,才可真正体会到Java的强大。

 

1、对象入门:

        对象是对现实世界的抽象。有状态(数据)和行为两部分组成。

 

        1.1 抽象的进步

                所有编程语言都是提供一种“抽象”方法。解决问题的复杂程度直接取决于抽象的种类及质量。这儿的“种类”是指准备对什么进行“抽象”。

                汇编语言是对基础机器的少量抽象。C语言是对汇编语言的一种抽象。但依然要求我们着重考虑计算机的结构,而非考虑问题本身的结构。在机器模型(位于“方案空间”)与实际解决的问题模型(位于“问题空间”)之间,程序员必须建立起一种联系。这个过程要求人们付出较大的精力,而且由于它脱离了编程语言本身的范围,造成程序代码很难编写,而且要花较大的代价进行维护。对一些早期语言来说,如LISP和APL,它们的做法是“从不同的角度观察世界”——“所有问题都归纳为列表”或“所有问题都归纳为算法”。PROLOG则将所有问题都归纳为决策链。对于这些语言,我们认为它们一部分是面向基于“强制”的编程,另一部分则是专为处理图形符号设计的。每种方法都有自己特殊的用途,适合解决某一类的问题。但只要超出了它们力所能及的范围,就会显得非常笨拙。

                面向对象的程序,可利用一些工具表达问题空间内的元素。由于这种表达非常普遍,所以不必受限于特定类型的问题。我们将问题空间中的元素以及它们在方案空间的表示物称作“对象”(Object)。OOP允许我们根据问题来描述问题,而不是根据方案。

 

        Alan Kay总结了Smalltalk的五大基本特征。这是第一种成功的面向对象程序设计语言,也是Java的基础语言。

                (1) 所有东西都是对象。

                (2) 程序是对象的组合;通过消息传递,各对象知道自己该做些什么。(方法?)

                (3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。

                (4) 每个对象都有一种类型。“类”(Class)是“类型”(Type)的同义词。一个类最重要的特征就是“能将什么消息发给它”。(方法?)

                (5) 同一类所有对象都能接收相同的消息。由于类型为“圆”(Circle)的一个对象也属于类型为“形状”(Shape)的一个对象,所以一个圆完全能接收形状消息。这意味着可让程序代码统一指挥“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包括“圆”。这一特性称为对象的“可替换性”,是OOP最重要的概念之一。(里氏代换)

                一些语言设计者认为面向对象的程序设计本身并不足以方便解决所有形式的程序问题,提倡将不同的方法组合成“多形程序设计语言”(注释②)。

                ②:参见Timothy Budd编著的《Multiparadigm Programming in Leda》,Addison-Wesley 1995年出版。

 

1.2 对象的接口

        “类型type”决定了接口,而“类class”是那个接口的一种特殊实现方式

 

1.3 实现方案的隐藏

        “类创建者”(创建新数据类型的人)以及“客户程序员”(在自己的应用程序中采用现成数据类型的人)        

        “接口”(Interface)规定了可对一个特定的对象发出哪些请求。只向客户程序员开放有必要开放的东西(接口),其他所有细节都隐藏起来。

        对象的职责就是决定如何对这条消息作出反应(执行相应的代码)。

        创建一个库时,相当于同客户程序员建立了一种关系。对方也是程序员,但他们的目标是组合出一个特定的应用(程序),

 

        控制对成员的访问。

                第一个原因是防止程序员接触他们不该接触的东西

                第二个原因是允许库设计人员修改内部结构,不用担心它会对客户程序员造成什么影响。接口与实现方法早已隔离开,并分别受到保护

        访问权限这个很值得体会。

                包访问默认“friendly”(友好的)涉及“包装”(Package)概念——即Java用来构建库的方法。

                子类只能覆盖public,protected的方法,其他都不行。子类覆盖的方法访问权限不能比父类的更小。里氏代换。

        protected,friendly百科,存在的意义。

????隐藏之后,客户程序员就不能接触和改变那些细节,所以原创者不用担心自己的作品会受到非法修改

“非法修改”这个怎么理解,具体指的什么操作?1、直接改源代码,NO?

2、通过子类覆盖实现类的public代码?

3、其他????

        封装:1、控制对内部细节的访问,即不能访问,安全

                2、不需要访问关心内部细节,方便,降低复杂度(难度),比如把一组语句封装成一个方法

 

 

1.7 对象的创建位置和存在时间

        C++存储以及存在时间可在编写程序时决定,只需将对象放置在堆栈(有时也叫作自动或定域变量)或者静态存储区域即可。

        第二个方法是在一个内存池(堆)中动态创建对象,位置和时间是运行期间动态执行的,不确定。

 

1.8 违例控制:解决错误

        错误控制一直都是设计者们需要解决的一个大问题。很难设计出一套完美的错误控制方案,许多语言干脆将问题简单地忽略掉,将其转嫁给库设计人员。对大多数错误控制方案来说,最主要的一个问题是它们严重依赖程序员的警觉性

 

 

2、一切都是对象

 

2.1 用句柄操纵对象

        对象的句柄即引用。

        有六个地方都可以保存数据(第五六不属于内存模型):

        (1) 寄存器。最快,位于处理器内部。寄存器是根据需要由编译器分配。我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹。

        (2) 堆栈。驻留于常规RAM(随机访问存储器)区域,但可通过它的“堆栈指针”获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移,则会释放那些内存。读写速度仅次于寄存器。创建程序时,Java编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上和向下移动指针。尽管有些Java数据要保存在堆栈里——特别是对象句柄,但Java对象并不放到其中(java句柄)。

        (3) 堆。动态创建对象,位置和时间是运行期间动态执行的,不确定。代价较高。

        (4) 静态存储。这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间。

        (5) 常数存储。常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格地保护,所以可考虑将它们置入只读存储器(ROM)。

        (6) 非RAM存储。若数据完全独立于程序之外如:“流式对象(字节流)”和“固定对象(文件)”。

 

2.2 特殊情况:

        基本类型数据,静态工具类,都不是对象。比如for 循环时的int i,显然比对象的integer快。1、数据小,2、在堆栈中。

        用new创建对象(特别是小的、简单的变量)并不是非常有效,因为new将对象置于“堆”里。对于这些类型,Java采纳了与C和C++相同的方法。也就是说,不是用new创建变量,而是创建一个并非句柄的“自动”变量。这个变量容纳了具体的值,并置于堆栈中,能够更高效地存取。

        堆栈要求的数据格式(长度)固定,所以基本类型,对象句柄可以存在堆栈里,对象的数据大小不确定,所以在堆里。

        primitive类型大小并不随着机器结构的变化而变化。这种大小的不可更改正是Java程序具有很强移植能力的原因之一。

 

2.3.1 作用域

        Scope作用域决定了变量的“可见性”以及“存在时间”。

        对象的作用域String s = new String("a string");句柄s会在作用域的终点处消失。然而,s指向的String对象依然占据着内存空间

 

this关键字

        Banana a = new Banana(), b = new Banana();

        a.f(1);b.f(2);

        若只有一个名叫f()的方法,它怎样才能知道自己是为a还是为b调用的呢?

        编译器会处理成这样的的:Banana.f(a,1);Banana.f(b,2);//a当前对象的句柄

 

static

        static方法并不是“面向对象”的,利用static方法,不必向对象发送一条消息,因为不存在this句柄。

 

finalize()

        假定我们的对象分配了一个“特殊”内存区域,没有使用new。垃圾收集器只知道释放那些由new分配的内存,所以不知道如何释放对象的“特殊”内存。GC之前它首先调用finalize(),可以在垃圾收集期间进行一些重要的清除或清扫工作。

        GC和finalize只和清理内存有关,不必过多使用。

 

第5章 隐藏实施过程

        Java访问控制的价值public,friend(默认),protected,private

                作为一名库设计者,应将所有东西都尽可能保持为“private”(私有),

                如何将发生变化的东西与保持不变的东西(公开给客户程序员的接口)分隔开。

 

        初始化顺序;private Person p = new Person(),通过断点,或者输出内容。

 

        数据成员(有时也叫“字段”)以及成员函数(通常叫“方法”)。

        类成员变量。成员变量。局部变量。

         fields (sometimes called data members), and methods (sometimes called member functions).

                对于任何关系,最重要的一点都是规定好所有方面都必须遵守的界限或规则。

 

第6章 类再生

        “继承”(Inheritance),涉及的大多数工作都是由编译器完成的。

        6.1组合:只需在新类里简单地置入对象句柄即可。 

                编译器并不为每个句柄创建一个默认对象,因为那样会在许多情况下招致不必要的开销。

        子类构造方法(不管带参无参)都需要明确调用父类的带参构造super(i);        

                编译器会强迫我们在衍生类构建器的主体中首先设置对基础类构建器的调用。这意味着在它之前不能出现任何东西。以为它首先是父类的,然后才是子类的。

        垃圾收集器回收时间不确定,而且具体jvm各不相同,jvm规范只是规定了接口。        

 

继承与组合:

        1、继承是属于关系,只能单继承,扩展新类新功能有局限性

        2、继承会破坏封装,父类的实现细节可以被重写,

        3、组合可以把成员对象当做一个属性来处理,不需要了解成员对象的内部细节。

        4、组合可以对成员对象设为public,然后用car.left.window.rollup();方式。

 

        程序开发是一个不断递增或者累积的过程,就象人们学习知识一样,项目看作一个有机的、能不断进步的生物。

        继承的一个好处是它支持“累积开发”,与修改现有代码的主体相比,改正错误所需的时间和精力就可以少很多(类的隔离,只需要关注新增代码)。

        Upcasting上溯造型,转换成父类的。

                创建Circle对象,并将结果句柄立即赋给一个Shape。这不是错误操作(将一种类型分配给另一个),而是Upcasting

        downcast向下转型,不安全,用instanceof(run-time-type-identity运行期类型检查)消除。

如何选择:

        是否需要从新类上溯造型回基础类(是否要用到多态)。若必须上溯,就需要继承;否则用组合。

                继承和抽象和多态联系更紧密。,

 

6.8 final关键字

        考虑到两方面的因素:设计或效率。

        final数据

                基本数据类型(Primitives),final会将值变成一个常数;

                对于对象句柄,final会将句柄变成一个常数,永远不能将句柄变成指向另一个对象(句柄的值可以看做对象的起始地址?地址不能变),但对象的值可变。

        final自变量

                可以修饰方法参数(自变量)void with(final Gizmo g) {//! g = new Gizmo(); // Illegal -- g is final...}

        final方法:禁止被子类覆盖,关闭动态绑定,效率更高

        final类:禁止被继承

 

第7章 多形性--用简洁的语句表达更多的语义

        将一个方法调用同一个方法主体连接到一起就称为“绑定”(Binding)。若在程序运行以前执行绑定(由编译器和链接程序,如果有的话),

        就叫作“早期绑定”。大家以前或许从未听说过这个术语,因为它在任何程序化语言里都是不可能的。C编译器只有一种方法调用,那就是“早期绑定”。

 

封装:只关注输入输出,不关心内部细节。

        1、package

        2、访问控制,public,private,protected,friendly

        3、内部类、作用域。

继承:

        它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

 

硬编码:将数字字符串常量强行编码到程序中,非常难以维护,硬编码数字通常称为“魔术数字”。

        可以用静态常量来改善,但是静态常量没有额外的类型安全性?用枚举?

 

7.6.9 为什么要用内部类:控制框架-由事件驱动的系统-GUI

        一个“应用程序框架”是指一个或一系列类,它们专门设计用来解决特定类型的问题

 

第9章 违例差错控制:违例堆栈

        9.1.1 违例自变量(对象==自变量?)

                throw new NullPointerException("t = null");创建一个不在程序常规执行范围之内的对象。

                对象实际会从方法中返回——尽管对象的类型通常并不是方法设计为返回的类型。

                违例对象返回的地方与从普通方法调用中返回的地方是迥然有异的(我们结束于一个恰当的违例控制器,

                它距离违例“掷”出的地方可能相当遥远——在调用堆栈中要低上许多级)。

                通常,唯一的信息是违例对象的类型,而违例对象中保存的没什么意义。

 

 

第10章 Java IO系统

        “对语言设计人员来说,创建好的输入/输出系统是一项特别困难的任务。”

        其中最大的挑战似乎是如何覆盖所有可能的因素。不仅有三种不同的种类的IO需要考虑(文件、控制台、网络连接),

        而且需要通过大量不同的方式与它们通信(顺序、随机访问、二进制、字符、按行、按字等等)。

        Java库的设计者通过创建大量类来攻克这个难题。事实上,Java的IO系统采用了如此多的类,以致刚开始会产生不知从何处入手的感觉(具有讽刺意味的是,Java的IO设计初衷实际要求避免过多的类)

 

第11章 运行期类型鉴定

        run-time-type-identity运行期类型检查:如果不知道一个对象的准确类型,RTTI会帮助我们调查。但却有一个限制:类型必须是在编译期间已知的

        只有基础类型的一个句柄时,利用它判断一个对象的正确类型(那个子类的)

 

11.1.1 Class对象(匿名对象?):包含了与类有关的信息

        每次写一个新类时,同时也会创建一个Class对象(更恰当地说,是保存在一个完全同名的.class文件中)。

        在运行期,一旦我们想生成那个类的一个对象,用于执行程序的Java虚拟机(JVM)首先就会检查那个类型的Class对象是否已经载入。若尚未载入,JVM就会查找同名的.class文件,并将其载入。

 

        static初始化工作是在类载入时执行的,

        有的JVM通过检查main()中的代码,已经预测到了对Candy和Cookie的需要,但却看不到Gum,因为它是通过对forName()的一个调用创建的,而不是通过更典型的new调用。

 

 

第12章 传递和返回对象

        12.1.1 别名问题

        “别名”意味着多个句柄都试图指向同一个对象,将句柄作为参数传递,别名问题就会自动出现,因为创建的本地句柄可能修改“外部对象”(在方法作用域之外创建的对象)。

        倘若创建一个会修改自己参数的方法,必须向用户明确地指出这一情况,应该尽量避免改变参数,或者从方法名上指出,减少混淆。

        不存在本地对象,只有本地句柄,句柄有自己的作用域,而对象没有

        java允许我们把对象句柄当做对象来处理

 

        只读对象可以很好地解决别名问题。比如String对象

        String类是final的,不可被继承。

        String类的对象被设计成“不可变”,和final class无关(String相关的方法都是创建一个副本,而不是直接修改String参数,包括“+”运算符)

 

 

第16章 设计范式

        范式:在全面了解特定问题后,提出一套灵活能够自我适应变化扩展的方案

        本质:添加一层新的抽象!只要我们抽象了某些东西,就相当于隔离了特定的细节,分离了变与不变。

        为设计出功能强大且易于维护的应用项目,通常最困难的部分就是找出我称之为“领头变化”的东西。

        继承可以想象成一种设计范式(类似一个由编译器实现的)。在都拥有同样接口(即保持不变的东西)的对象内部,它允许我们表达行为上的差异(即发生变化的东西)。合成亦可想象成一种范式,因为它允许我们修改——动态或静态——用于实现类的对象,所以也能修改类的运作方式。

        所有方案的组织都围绕“程序进化时会发生什么变化”这个问题展开

                系统不仅更易维护(而且更廉价),而且能产生一些能够重复使用的对象

        设计应该趋于简化,若设计过于复杂,就制作更多的对象

 

        class Info {

                  int type;

                  // Must change this to add another type:

                  static final int MAX_NUM = 4;

                  double data;

                  Info(int typeNum, double dat) {

                    type = typeNum % MAX_NUM;

                    data = dat;

                  }

        }

        static Trash factory(Info i) {//负责解决的“领头变化”问题:如果向系统添加了新类型(发生了变化),

        //唯一需要修改的代码在Factory内部,所以Factory将那种变化的影响隔离出来了。

    switch(i.type) {

              case 0:return new Aluminum(i.data);

    }

        Trash.factory(new Info((int)(Math.random() * Info.MAX_NUM),Math.random() * 100)));

 

 

 

附录D 性能

 

Java语言特别强调准确性,但可靠的行为要以性能作为代价。这一特点反映在自动收集垃圾、严格的运行期检查、完整的字节码检查以及保守的运行期同步等等方面

编译器可高效地连接字串(优化),但字串变量不能优化

 

 

D.3.2 依赖语言的方法

各种运算的执行时间除以花在本地赋值上的时间,最后得到的就是“标准时间”。

运算 示例 标准时间

本地赋值 i=n; 1.0

实例赋值 this.i=n; 1.2

int增值 i++; 1.5

byte增值 b++; 2.0

short增值 s++; 2.0

float增值 f++; 2.0

double增值 d++; 2.0

空循环 while(true) n++; 2.0

三元表达式 (x<0) ?-x : x 2.2

算术调用 Math.abs(x); 2.5

数组赋值 a[0] = n; 2.7

long增值 l++; 3.5

方法调用 funct(); 5.9

throw或catch异常 try{ throw e; }或catch(e){} 320

同步方法调用 synchMehod(); 570

新建对象 new Object(); 980

新建数组 new int[10]; 3100

 

 

堆栈的大小是规则的,堆中对象大小不一致,内存碎片整理,是个大问题。

C++中,对象是在堆栈中创建的。这样可达到更快的速度,因为当我们进入一个特定的作用域时,堆栈指针会向下移动一个单位,为那个作用域内创建的、以堆栈为基础的所有对象分配存储空间。而当我们离开作用域的时候(调用完毕所有局部构建器后),堆栈指针会向上移动一个单位。然而,在C++里创建“内存堆”(Heap)对象通常会慢得多,因为它建立在C的内存堆基础上。这种内存堆实际是一个大的内存池,要求必须进行再循环(再生)。在C++里调用delete以后,释放的内存会在堆里留下一个洞,所以再调用new的时候,存储分配机制必须进行某种形式的搜索,使对象的存储与堆内任何现成的洞相配,否则就会很快用光堆的存储空间。之所以内存堆的分配会在C++里对性能造成如此重大的性能影响,对可用内存的搜索正是一个重要的原因。所以创建基于堆栈的对象要快得多。

 

JVM还采用了其他许多加速方案。其中一个特别重要的涉及装载器以及JIT编译器。若必须装载一个类(通常是我们首次想创建那个类的一个对象时),会找到.class文件,并将那个类的字节码送入内存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值