首页 > 代码库 > 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(一)