java OOP及相关基础知识汇总(转)

OOP

  • 对象有三个要素

    • behavior

      • 接口是怎样的,有什么方法/field可以用?
    • state
      • 调用方法的时候,对象会有什么反应?
      • 只有通过调用方法才能改变一个对象的state
    • identity
      • 对象之间如何区分?
  • 类的三大关系
    • dependence

      • uses-a
      • 在方法里用到的类(方法的local variable)
      • 应当尽可能地少
    • Aggregation
      • has-a
      • 自己本身有的类(自己的field)
    • Inheritance
      • is-a
      • general v.s. specialized

Java自带类的入门

  • 只封装了functionality的Math
  • Date
  • GregorianCalander

Java OO初步 - 以Date为例

  • Date的API文档
  • Date是用来表示某一个时刻而不是某一个现实世界的时刻的(设计的初衷是UTC时间,但是又没有遵守一些复杂的历法规则)
  • 用来表示现实世界时间的另有一些其他类,比如GregorianCalander(常用的公历),这样方便不同的locale用不同的历法,它们都继承Calendar(相对于太general的Date而言,一个Calendar加上一堆子类确实是更好的设计……)
  • derefernce一个null会在runtime抛出error
  • 所有的Java对象都被放置在
  • 和JS类似,Java对象都是引用,=只会得到shallow copy,需要deep copy的时候需要调用Object均带有的clone()

Java OO初步 - 以GregorianCalander为例

  • API
  • 月份从0数起,为了防止出错以及减轻对底层实现的依赖,传月份的时候最好使用Calendar这个虚类的常量,比如Calendar.DECEMBER,星期的名字也是一样
  • get和set需要将相关的field通过参数传入而不是直接调用不同名字的方法,相关的field用Calendar的常量表示 e.g. deadline.set(Calendar.YEAR, 2014)
  • add可以修改时间,负数的增量表示倒退
  • setTimegetTime可以用来完成Calander和Date之间的转换
  • 有一个DateFormatSymbols用来获取当前locale关于日期的一些名字,比如星期一叫什么(Monday(英文)?星期一(中文)?)

自定义类

  • main函数需要寄存在一个类里
  • 一个文件里只能有一个public类,其他类可以有多个。文件名必须和自己的public类的名字相同
  • Java编译器自带类似于make的功能,会查找依赖,如果没有找到.class会自动找对应的.java并编译,或者如果.java修改过了也会重新编译
  • 构造函数要且必须要用new来调用,直接用会在编译时报错
  • 虽然方法内声明的变量不存在shadow,但是方法参数的名字和类自带field的名字可以存在shadow(此时自带的field需要加上this),不过参数名不能再用来声明新的local变量
  • this和JS里的用法一样,后面跟点
  • Java里所有类的实现都和类的声明写在一块儿,长得类似C++的inline声明,只不过在Java里决定是否inline是编译器的活
  • 在方法内返回类的field时,如果它是对象,Java不会做一个deep copy再返回,所以实际上返回的是这个对象的引用,会破坏封装。为此需要返回它的.clone()的返回值

Static

  • Java里类中的常量使用也final声明,和C++不同的是,它在整个构造函数里都可以被修改(C++里常量一定要通过member initializer这种诡异的方法去设置,到函数体里就不能动了),出了构造函数才不能动
  • Java标准库里那些标了native的函数是可以绕过Java自己的语法限制的,比如一个API里说是final的field还可以用某些方法修改(因为native的函数不是用Java实现的(通常是C/C++),所以可以绕过这个限制)
  • Java的static方法和C++一样,没有this,不能调用非static的方法,也不能使用非static的field。同样地,static方法不一定只能用类名调用,也可以随意用一个这个类的对象调用,虽然这种做法比较confusing所以不推荐
  • 为一个方法标明static大约有两种情形
    • 这个方法不改变对象的状态,所以不需要修改nonstatic filed
    • 这个方法只需要访问static的field
  • 作者吐槽了一下static这个名字的三重含义2333 (C里面可以指只初始化一次的变量(最符合static字面意思的意义),或者只有当前文件能访问的变量。到了C++又加上了一个类里共有的成员的意思,也是java唯一沿用的含义)
  • 在Java里,访问权限的设置和C++类似,同一个类对象可以访问彼此的private成员,子类不能访问父类的private成员,但是Java的继承只有public一种,没有那堆复杂无比的规则
  • 顺带介绍了一下factory模式
  • main函数也必须是static的。注意每个类都可以有main函数,这样方便做单元测试。在运行的时候,只会用入口的.class里的main函数,其他类的main函数会被无视。这样的话,如果要跑一个叫ClassA的类的单元测试,可以在这个类里写个main函数,然后执行
    $ java ClassA

    如果要跑用了多个类,包括ClassA的程序,入口写在Runner.java里,可以跑

    $ java Runner

    这样ClassA的main函数就会被无视。注意这里可能还需要加上classpath说明怎么找到ClassA和其他类。另外,private类也可以有main函数,只要声明是

    public static void main(String[] args)

    就行了。

参数

  • Java和JS一样,一切都是call-by-value,函数参数传进来的引用内容可以改,引用指向的对象不能改,原始类型不是引用就是直接copy再传进来了,怎么动都没事

对象的构造

  • Java和C++一样,用signature实现函数重载
  • 所有field都会有默认初识值(数字是0, boolean是false,对象是null)。注意是field才会有默认值,不初始化也能用,local变量是没有的,不初始化就不能用。
  • 和C++一样,没有构造函数的时候会提供一个默认构造函数
  • 在Java里用来给field直接赋值的构造函数参数名的几种convention是
    • 用首字母,小写
    • 开头加a,驼峰
    • 直接同名,这时候会产生shadow,所以在指定field的时候要加this
    • 没有C++那种加下划线的convention
  • Java里构造函数居然可以互相调用 =口= 用法是
    this(...)

    然后就会根据传进去的参数匹配对应的构造函数。这个调用一定要写在构造函数的第一句。这样一来如果很多构造函数都有相同的代码,就可以抽象到某一个构造函数里,然后大家一起调用它。

  • 可以在类声明里直接给field写上初始值,这个初始化可以在构造函数前执行完,所以如果有一些field需要一个很多构造函数都会给它的初始值,可以在类声明里面写,就不用在N个构造函数里都写了。注意这个初始值还可以是某个函数的返回值,不一定需要是literal。
  • 如果光用一个函数返回值还不足以初始化,那么还可以用上initialization block,里面就可以写语句了,参见Initializing Fields (The Java™ Tutorials > Learning the Java Language > Classes and Objects)
  • initialization block和field的声明不一定有先后,可以夹杂起来的,而且没有声明的field还是不能初始化的,这里有一堆复杂的规定(复杂到早期的java编译器自己都有些不符合speciation的地方),一般来说建议把所有声明都写完再写initialization block
  • 初始化的顺序大约是
    1. 先赋默认值
    2. field initializer和initialization block按照在代码里出现的顺序执行
    3. 如果这个构造函数还调用了另一个构造函数(人家要写在第一行),调用它
    4. 最后执行这个构造函数的函数体
  • static field还可以通过一个static initialization block初始化,只要在花括号前写上static就行。
  • static initialization block会在这个类第一次load的时候执行,所以如果你在里面写上输出hello world的语句,你就可以在没有main函数的情况下输出hello world = =虽然运行时会会在执行完static initialization block里的语句后报错main函数没有定义。如果你还想逃脱这个报错,只要加上System.exit(0)就好(这样玩真的有意思吗喂!!)

对象的析构

  • Java里没有析构函数,但是可以有一个叫finalize的方法,在每次GC清理对象的时候会执行。不过这个方法执行的时机是不确定的,所以不能依赖它回收资源。最好的方法就是直接在任何申请了资源的函数里及时回收。
  • Java的GC和JS差不多,用的是Mark and Sweep,所以无法确定finalize何时被调用

package

  • java的类可以放在package里分发,package的命名方式通常会按照所属机构的域名倒着写,所以你会经常看到叫com.xxx.yyy的pacakage,制作这个package的人所在的机构的网站域名就会是xxx.com
  • 嵌套的package没有包含关系,java.util和java.util.jar里的类是不一样的。
  • 调用一个package的类可以每次指明它都写上全名,也可以先import它进来就不用写前面的package的名字了。import一定要写在文件开头。
  • import可以用 * 来获得一个package的所有类,eclipse提供将 * 展开成文件里使用过的类名的功能。注意 * 只能用来指一个package的所有类,不可以放在上一级指多个package
  • bytecode里会把所有类名展开全,java编译器和C++编译器的区别注意在于C++的编译器不会看被#inlcude的文件的内容,而java会看被import的类的代码
  • import还可以用来获得一个类的public static的方法或者field,这时需要写类似import static package.class.method的语句(注意import后跟static)。如果想import全部static成员,用 * 就行。
  • 如果想将一个新的类加入现存的package里,可以在这个类的声明前写上
    package packageName

    在指定的package里将这个类塞进去。如果不写,这个类就会放进default package里

  • 放在package里的类编译得到的bytecode需要按照package的名字创建好目录结构(每个点分割的元素加一层文件夹),放在项目根目录下。这样JVM就知道去哪里找这个类的bytecode(这里假设根目录会加进classpath里)。
  • 这个package的查找是在运行时进行的,编译器不会去检查,JVM才会。
  • 一个类里可以引用同一个package的其他类和其他package的public类。注意类名前不写modifier默认是private,但是类的field前不写默认是public(和C++相反)。很多人会忘记写上private,于是同一个package的所有类都可以随便获得这个field了,Java标准库里的java.awt.Window的warningString就是这样一个field呵呵呵呵,而且这个bug一直没被解决(作者自黑了一把:我们在core java第八版都说过这个bug了他们还没改,显然java标准库的维护者们都不看我们的书呢2333)
  • 对于存在这种笔误的field,你可以通过设置文件目录+使用package来偷偷修改掉这个field,比如利用前面提到的标准库里的bug,你可以突破封装,修改标准库里的warningString 23333 不过从JDK 1.2开始所有java.开头的package都被seal起来不能用package改了,算是亡羊补牢。

class path

  • .jar其实也是一种ZIP格式,所以能够打开ZIP的软件也能用来打开或者解压.jar。里面通常是一个按照package的名字构造好的目录结构,里面按规则放着.class和其他文件,这样可以省空间。
  • JVM寻找类的时候会从class path里列出来的目录开始按package的名字结构去找。class path可以在编译指令里用-classpath(缩写-cp)设置,也可以在环境变量CLASS_PATH里设置一个通用的列表
    • 注意当运行指令里没有-classpath的时候,默认的class path包括运行时的工作目录。但是如果有设class path,工作目录是不会默认出现在里面的,此时有两种解决方案

      1. 在class path里直接加上工作目录,比如在Unix-like系统下

        $ java -cp .:dir1:dir2:dir3:dir4...  className

        开头的点就表示工作目录,Unix-like系统下用冒号分割(在win下用分号)

      2. 在环境变量CLASS_PATH里直接加上那个点,就不用每次写编译指令都设进去了
    • 注意随便设环境变量不是好事,而且一旦指明了CLASS_PATH又不在里面加上点,每次跑的时候class path总会缺了当前目录——苹果的QuickTime installer曾经干的好事
    • 编译器(javac)总是会检查当前目录的,不会检查的是运行时(java)
    • 注意class path里的wildcard用法和linux下的不同,* 不能随便乱用,参见 Java SE Documentation: Setting the class path
  • runtime库里的文件和jar会自动加进class path
  • JVM的查找顺序是
    1. 在runtime库里查找(比如jre/lib)
    2. 在class path里嵌套的package里找
    3. 从当前目录开始查找
    4. 从class path里指明的jar里查找
  • Java编译器的查找
    • 编译器会参考所有import语句来搜索
    • 编译器会以class path里指明的每一个目录为起点,展开import语句去搜索
    • 编译器找到更新过的代码也会自动重新编译
    • 当找到多个重名的类的时候会报编译时错误
    • 因为一个文件只能有一个public类,而且文件名还要和类名一样,所以编译器查找文件的时候会方便很多。但是如果在同一个package里,一个类是可以import同一package的其他private类的,这个时候要靠编译器去把这个package里的文件都看一遍才行。
    • 所以Java编译器的查找虽然不那么需要在class path里写明一堆目录,但是慢很多

注释

  • Java有一个很吊的工具,叫做javadoc,写法参见这里这里。只要按照约定好的方式去写注释,用javadoc跑一遍就能自动生成HTML文档。JDK6的官方API文档和hadoop的官方API文档都是用这个生成的。
  • JDK6生成的样式长得太蛋疼了,自己魔改了一个css在这里。好在javadoc生成的文档会共用目录下的一个stylesheet.css,通过修改它就可以影响这一套文档的外观。

Before

After

一些tips

  • 当一个类里有太多个基本类型的field的时候,说明可能有一些field本身就可以组成一个类然后再加进来了。

http://www.cnblogs.com/joyeecheung/p/3859430.html

时间: 2024-10-06 10:22:56

java OOP及相关基础知识汇总(转)的相关文章

沉淀,再出发:Java基础知识汇总

沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的语法,对象的定义,类.接口.继承.静态.动态.重载.覆盖这些基本的概念和使用方法,到稍微高级一点的多线程,文件读写,网络编程,GUI使用,再到之后的反射机制.序列化.与数据库的结合等高级一点的用法,最后将设计模式应用其中,产生了一个个新的概念,比如Spring.Spring MVC.Hibernat

【RAC】RAC相关基础知识

[RAC]RAC相关基础知识 1.CRS简介    从Oracle 10G开始,oracle引进一套完整的集群管理解决方案—-Cluster-Ready Services,它包括集群连通性.消息和锁.负载管理等框架.从而使得RAC可以脱离第三方集群件,当然,CRS与第三方集群件可以共同使用. (1).CRS进程 CRS主要由三部分组成,三部分都作为守护进程出现 <1>CRSD:资源可用性维护的主要引擎.它用来执行高可用性恢复及管理操作,诸如维护OCR及管理应用资源,它保存着集群的信息状态和OC

网络连接相关基础知识笔记

一.常说的TCP/IP的含义 TCP/IP协议簇并不仅仅指TCP协议和IP协议,实际它包括了一系列协议组成的集合,如:TCP,IP,UDP,FTP,SMTP,DNS,ARP,PPP等 TCP与UDP协议都属于传输层协议,但有很大不同,TCP是面向连接的协议,提供的是可靠的数据流服务,TCP采用"带重传的肯定确认"机制来实现传输的可靠性,实现了一种"虚电路",因为从物理上来说,并不是真正在两台主机间建立了连接,这种连接只是存在于逻辑上的.最大的开销出现在通信前建立连接

Java多线程完整版基础知识

Java多线程完整版基础知识 (翟开顺由厚到薄系列) 1.前言 线程是现代操作系统中一个很重要的概念,多线程功能很强大,java语言对线程提供了很好的支持,我们可以使用java提供的thread类很容易的创建多个线程.线程很不难,我对之前学习过的基础,在这做了一个整理,本文主要参考的是Java研究组织出版的j2se进阶和张孝祥-java就业培训教材这两本书 2.概述 2.1线程是什么 主要是线程与进程的区别,这里不再阐述,自行网上搜索 为什么使用线程:操作系统切换多个线程要比调度进程在速度上快很

Java中String的基础知识

Java中String的基础知识 ==与equal的区别 基本数据类型,指的是java中的八种基本数据结构(byte,short,char,int,long,float,double,boolean),一般的比较是使用的 ==,比较的是他们的值. 复合数据类型(类) ==比较的是两个对象的引用,可以理解为在内存中的地址,除非是同一个new出来的对象,他们的 ==为true,否则,都为false. equal是object中的方法.object中的实现如下,内部还是使用==实现,也就是说,如果一个

[基础] Java目录(摘自Java核心技术·卷1 基础知识)

Java核心技术·卷1 基础知识(原书第9版) 第1章 Java程序设计概述 1.1 Java程序设计平台 1.2 Java"白皮书"的关键术语 1.2.1 简单性 1.2.2 面向对象 1.2.3 网络技能 1.2.4 健壮性 1.2.5 安全性 1.2.6 体系结构中立 1.2.7 可移植性 1.2.8 解释型 1.2.9 高性能 1.2.10 多线程 1.2.11 动态性 1.3 Java applet与Internet 1.4 Java发展简史 1.5 关于Java的常见误解

深入理解mysql之BDB系列(1)---BDB相关基础知识

    深入理解mysql之BDB系列(1) ---BDB相关基础知识 作者:杨万富 一:BDB体系结构 1.1.BDB体系结构 BDB总体的体系结构如图1.1所看到的,包括五个子系统(见图1.1中相关数).1)数据存取子系统,2)事务子系统,3)锁子系统,4)内存池管理子系统,5)日志子系统. 在一个应用程序中,并不一定须要全然具备这5大子系统. 假设程序仅仅使用了数据存取子系统,它的体系结构如图1.2.在图1.2中,我们仅仅使了两个子系统:数据存取以及内存池子系统.(备注:另外三个子系统在B

Delphi基础知识汇总

☆Delphi基础数据类型 分类 范围 字节 备注 简单类型 序数 整数 Integer -2147483648 .. 2147483647 4 有符号32位 Cardinal 0 .. 4294967295 4 无符号32位 Shortint -128 .. 127 1 有符号8位 Smallint -32768 .. 32767 2 有符号16位 Longint -2147483648 .. 2147483647 4 有符号32位 Int64 -263 .. 263 8 有符号64位 Byt

图像增强相关基础知识

图像增强处理-1 图像增强是图像处理中一个重要的内容,在图像生成,传输或变换的过程中,由于多种因素的影响,造成图像质量下降,图像模糊,特征淹没,给分析和识别带来困难.因此,按特定的需要将图像中感兴趣的特征友选择地突出,衰减不需要的特征,提高图像的可懂度是图像增强的主要内容.图像增强不考虑图像降质的原因,而且改善后的图像也不一定逼近原图像,这是它与图像复原本质的区别.图像增强的主要目的有两个:一是改善图像的视觉效果,提高图像的清晰度:二是将图像转换成一种更适合人类或机器进行分析处理的形式,一边从图