首页 > 代码库 > C++ 程序员学java(一)

C++ 程序员学java(一)

构造与析构

l  可定义初始化函数,但类内部所有变量会先于初始化函数初始化。

l  可以在类体内直接定义变量时直接初始化变量。

l  类中变量定义的顺序就是初始化的顺序

l  类构造时先构造所有的预定义变量,然后调用构造函数

l  垃圾回收机制不但会回收内存,还会将数据结构移动到紧凑的区域。在少量垃圾时采用标记清除法,不进行内存移动。

l  当在构造函数内用this调用其他构造函数时,必须要再第一句,且只调用一次。其他函数不可用this调用构造函数。

 

语法

l  break和continue后面可跟label

l  for可以有foreach语法

l  java没有sizeof

l  /**开始书写javadoc,可用@等语义

l  静态语句可以{}组合成一个静态块,只会执行一次。

l  enum有toString、ordinal、values方法

l  try...finally保证try块中的代码无论如何退出,finally中的代码一定会执行

l  final可以让基本类型和引用保持不变,但是不能让对象本身保持不变。java不提供这种功能。final使用前必须初始化。

l  final用于方法时是希望不被子类覆盖,因此private方法全部是隐式的final方法

l  final用于类表示它不可以被继承,因此其中的所有方法也是隐式final的

l  for的foreach语法可用于容器

l  所有异常有两个构造函数,一个不接受任何参数,一个接受字符串

l  在函数参数后面使用throws进行异常说明

l  java不允许重载任何操作符

l  static import可以将包导入当前域,之后使用不用加包路径

l  enum定义的其实一个继承自java.lang.Enum的类,其是一个有一些限制的普通类,可以定义方法。由于java不支持多重继承,所以enum不能继承其他类,但是可以实现接口

l  enum的每个实例可以定义同一方法的不同实现,只要在enum定义中将该方法定义为abstract

l  使用volatile关键字可以获得针对该资源的读写原子性

l  synchronized关键字可以获得原子性的域和代码段(临界区)

动态类型检测

l  每个类都有一个class对象

l  instanceof可以RTTI判断对象的类型,并且只可以与命名类型比较,不可以与Class对象比较。Class.isInstance也可以发挥与instanceof关键字一样的功能

l  instanceof和Class对象对类型的判断的一个重要区别是instanceof考虑子类,而Class对象认为子类和基类是不同的类型

l  Class类的getMethods()和getConstructors()方法分别返回Method对象和Constructor对象的数组

l  Class.forName()生成的结果在编译时是不可知的,所有的方法特性签名都是在执行时被动态提取出来的。该方法的作用是查找并加载指定的类,获得其方法列表,用以支持反射。

l  没有任何方法可以对反射隐藏方法,哪怕是private。通过Class获得Method对象后,设置Method的setAccessible(true)就可以使任何方法变为可用。即使编译后的代码,也可以通过javap –private显示私有的方法的名,从而可以调用。

l   

 

数组与可变参数列表

l  定义数组时不允许指定数组的大小(因为定义的是数组引用)。

l  数组引用可以直接等号互相赋值,但是指向的是同一个数组

l  数组有一个固定的域:length,表示数组的长度

l  java可以用数组和可变参数列表语法两种方式来实现可变参数列表

l  函数可以直接返回一个数组引用,不用担心内存问题。jvm会在用户不需要的时候才回收其内存

l  复制数组应该使用System.arraycopy(),该函数对各种类型都做了优化重载

l  数组的比较使用Arrays.equals()进行,排序使用Arrays.sort()函数,Arrays.binarySearch()函数只针对已经排序的数组进行查找,未经过排序的查找结果未知

l  Arrays.asList()可以将数组转换为List

 

包与访问权限

l  代码以包的形式组装,每个编译单元可以有一个与文件同名的类,且只有该类对外可见,且以public修饰,且最多只有一个,可以没有,没有时文件名随意。

l  类的访问权限只有包访问权限和public访问权限。

l  一组编译单元可以定义到一个包中,在编译单元文件的开头用package关键字加包名。

l  包路径一般是域名的颠倒加文件路径

l  类的访问权限包括public、private、protected和包访问权限(friendly),包访问权限是默认的,表示同包中的其他类都可以访问,包外不可以。

l  使用类的用户也无法访问包访问权限

l  在同一个目录下,没有指定包,则为该目录的默认包内容。

l   

接口和内部类

l  接口可以包含域,但域为隐式的static和final

l  类用implements关键字实现interface

l  interface关键字定义的接口前面也用public修饰,不修饰为包访问权限

l  在interface中的所有方法默认都是public的,并且只能是public的

l  子类可以继承多个接口,但只能继承一个基类

l  可以用子接口继承父接口

l  组合继承多个接口时,各个接口方法的名称不能相同

l  在接口中定义的域必须初始化,而且可以用非常量表达式初始化

l  接口可以嵌套进接口或者类,当嵌套进类时可以定义为private

l  内部类拥有外围类所有元素的访问权限

l  内部类中获得外部类的引用的方式是: 外围类.this

l  非静态内部类的创建必须要首先创建外围类,静态内部类(嵌套类)不需要

l  不能从嵌套类中访问外围类的非static域

l  外围类外部创建内部类时要使用: 外围类.new 语法

l  内部类函数想要使用外部定义的对象,则该函数参数必须为final修饰

l  匿名内部类必须继承一个父类或实现一个接口

l  可以在interface中实现内部类,此时的内部类自动是public和static的嵌套类

l  多层内部类可以对任意上层类具有完全访问权限

l  内部类被继承,必须在孙子类中手动调用爷爷类的构造函数,因为父类(内部类)默认有一个指向爷爷类的引用。: fulei.super()

l  可以定义局部内部类,该内部类可以访问方法中之前的所有域以及外围类的域

l  接口对类信息的隐藏并不完整,如果用户使用RTTI仍可以调用具体类的具体方法。对应的策略应该是彻底的对用户隐藏方法,只对interface可见(例如包访问权限)

 

机制

l  编译单元文件以.java结尾,编译成机器码后以.class结尾

l  java没有条件编译功能

l  所有的类文件只有在被用到的时候才会发生加载,而其中的static域只有在加载时才初始化

l  java中除了static和final(private)函数,其他函数都是后期绑定(动态绑定)

l  所有类型转化都会在运行时经过检查,不通过检查会抛出ClassCastException异常

l  Java泛型是用擦出来实现的,List<String>、List<Integer>在运行时是同一个类型,都是List

l  如果想要继续持有对象的引用,但又希望在内存不足时垃圾回收机制能够回收该对象,需要使用Reference对象。SoftReference、WeakReference、PhantomReference由强到弱

l  后台线程生成的线程也是后台线程,前台线程如果全部结束,后台线程会全部退出,但后台线程退出不会影响前台线程。

l  java的递增操作不是原子操作

 

继承

l  继承使用extend关键字

l  子类中访问父类域用super关键字

l  子类中重载了父类的函数并不会覆盖父类的函数(C++会)

l  基类的private方法子类可以定义同名函数,但是不是覆盖,而是全新的函数

l  子类可以定义与基类同名的变量,但是是全新的变量,访问时必须要限定

l  在构造函数中不应该调用动态绑定函数(也即普通函数)

l  子类可以有协变返回类型

l  有抽象方法的类是抽象类,该类也必须用abstract限制

容器

l  容器分为Collection和Map两种

l  新程序不应使用已经过时的Vector、HashTable、Stack

l  Set是一种Interface,其具体实现有HashSet、TreeSet、LinkedHashSet等

l  Queue有LinkedList、PriorityQueue

l  Map接口有HashMap(搜索)、TreeMap(排序)、LinkedHashMap(迭代)、WeakHashMap(允许回收)、ConcurrentHashMap(并发)、IdentityHashMap实现

l  当在使用容器的过程中如果其他线程修改了本容器,会抛出ConcurrentModificationException异常

其他常用库操作

l  标准输入输出中System.out和System.err都可以直接使用,而System.in是一个未经过包装和加工的InputStream。

BufferedReader stdin = new BufferedReader(newInputStreamReader(System.in))

l  setIn(InputStream)、setOut(PrintStream)、setErr(PrintStream)用来给标准输入输出重定向

l  使用OSExcute.command()执行系统命令

l  Externalizable接口不序列化,如果非该接口类可以用transient逐个修饰不想被序列化的域,或者是实现自己的writeObject()和readObject()函数。

l  EnumSet终于可以把枚举体面的放到set里了。EnumMap则可以创建更有意义的map键值

l  定义任务需要继承Runable接口,并在类中重定义run()函数,该函数就是函数体。但是想要产生线程必须要将一个任务附加到一个线程Thread t = new Thread(new Task),然后调用t.start()开始线程,如此Task中的run函数就被调用了。

l  调用任务的另一个方法是使用Executor,该机制可以使一个ExecutorService管理所有的任务。另外,Executor还可以调用Callable接口的call方法生成线程。必须使用ExecutorService.submit()调用

l  Thread.yield()函数强制让调度器起作用。sleep让出CPU资源让调度器起作用

l  使用Thread.currentThread().setPriority()设置当前线程的优先级。

l  使用Thread.setDaemon(true)将当前线程设置为后台线程

l  使用Thread.join()函数让一个线程等待另一个线程结束后才继续执行

l  对资源加锁可以用synchronized关键字或者java.util.concurrent库

l  java中有提供原子类:AtomicInteger、AtomicLong、AtomicReference等

 

tricks

l  将类的所有构造函数声明为private,则没有人能创建该类,除了本类的static方法

l  使用类功能时应使用组合,使用类接口时应使用继承

l  final static命名的变量全部大写,并且以下划线分割

l   

 

 

不足

l  java的数组访问检查、垃圾回收和必须要new对象效率上太差。

l  所有类变量预初始化多此一举

l  全后期绑定的策略太扯了

l  任何封装都无法阻止反射机制获得私有的函数

l  很容易被反汇编

l  泛型太差,甚至无法和数组一起工作

优点

l  interface、implement、extend关键字很好

l  充分利用文件名和路径构成的包路径的思路很好

l  for的foreach写法很好(C++11已经借鉴)

l  全部都是类的要求很好

l  框架的生成与使用很好(目前的C++也可以做到,但暂没人做)

l  广泛的、集成到IDE的、统一的库支持很好,目前C++各种库组织太分散

l  java库的实现明显是有组织有纪律的,充分考虑实际应用。例如广泛存在的toString

l  java为每个类都实现了class对象,如此的动态类型变得很容易,更富想象力。但也带来了效率问题。如果所定义的类大部分都只有几个对象,那么这种成本太高,但如果对象是批量的,并且RTTI能带来很大的优势,就可以采用。最好是允许编程时指定是否采用。侧重大型工程和库的对这个功能的需求很大。而且该特性能实现反射,而反射是动态编程的新世界的钥匙

l  将序列化集成到语言内部

l  枚举类型很强大,甚至可以定义方法。如此状态机本身可以执行转换了

l  java中实现很多批量操作,尤其是对字符串和打印信息的更高程度的语言集成

l  JavaBeans可以很方便的用组件生成程序,C++缺少如此一种与IDE紧密配合的条款

C++ 程序员学java(一)