JAVA程序设计<5>

1.Java程序设计基本概念

1.1 JVM

ClassLoader(类加载器):每一个java文件都对应一个java类,根据程序需要逐渐载入内存。(一般ExtClassLoader加载java的扩展API即/lib/ext中的类,APPClassLoader用来加载用户机器上的CLASSPATH设置的目录中的class)。

ClassLoader加载流程:当程序运行时,JVM启动,运行 bootstrap classloader(启动类加载器),该ClassLoader加载Java核心API(Extclassloader和AppClassLoader也在此时被加载),调用Extclassloader加载扩展API,最后Appclassloader加载CLASSPATH目录下定义的class。----一个程序最基本加载流程

JVM内部,统一使用编码是Unicode表示,编码转换只能发生在边界地方,JVM和OS的交界处,也就各种输入输出(或者Reader,Writer类)起作用的地方。(所以面向字节和面向字符有差别)

1.2 i++

i++是程序完毕后自增,++i是程序开始前自增

i=0;i=i++ + ++i=0+2=2

1.3 类型转换

布尔型 数值型 字符型

低级转高级自动转化(如果是char类型转高级类型,自动转对应ASCII码)

强制类型转化:(类型)变量名

包装类过度类型转化

字符串与其他类型转化(toString()转字符串)

1.4 程序结构

assert(表达式) 断言

1.5 运算符

&   &&(和前面一个&区别是只要前面false后面无需判断)

1.6 异常

java程序运行时出现的非正常现象,这种情况称之为运行错误。  Error(由java虚拟机生成并抛出5)和Exception

final(变量值不变或者对象引用不变)、finall、finalize(最多运行一次)

1.7 反射----是指程序可以访问、检测和修改它本身的状态或行为的一种能力。

反射允许在编写与执行时,使程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选中的的类协作代码。需要注意的是如果使用不当,反射的成本会很高。

java中的类反射Relectiion是java程序语言开发的特点之一,它允许运行中的java程序对自身进行检查,并能直接操作程序的内部属性。

2 Java内存管理

2.1垃圾收集

显示的分配内存和释放内存常常引起“内存泄漏”,因此,java在创建对象时会自动分配内存,并在该对象引用不存在自动释放内存。

垃圾收集器技术监视java程序运行。java使用一系列软指针来跟踪对象的各个引用,并用一个对象表将这些软指针映射为对象的引用。使用软指针,Java的垃圾收集器能够以单独的线程在后台运行,并依次检查每个对象。(标记对象、移除对象、移动对象或检查对象)

java语言中,判断一块内存空间是否符合垃圾收集器手机标准只有两个条件:(1)给对象赋予了null空值以后再也没有调用过;(2)给对象赋了新值,即重新分配了内存空间。

(提醒:一块内存空间符合垃圾收集器的收集标准,并不意味着这块内存空间就一定被垃圾回收器回收。)

垃圾回收注意几点:

1)不要试图假定垃圾回收时间,未知的。

2)Java中提供一些和垃圾回收打交道的方法,而且还提供强制执行垃圾回收的方法--调用System.gc(),但是该芳芳同样是不确定的方法。(并不能保证调用就一定能启动来及回收,只是向JVM发出请求,一切未知)

3)挑选合适的垃圾收集器。(一般使用JVM默认选项,但,,)

4)内存泄漏问题(内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用),对象都是有生命周期的,有的长,有的短,如果长生命周期的对象持有短生命周期的引用,就很可能会出现内存泄露)。良好的编程习惯和严谨的变成态度。

在Java程序中,我们通常使用new为对象分配内存,而这些内存空间都在堆(Heap)上。

此处借用别人的例子:

    public class Simple {
        Object object;
        public void method1(){
            object = new Object();
            //...其他代码
        }
    }

method1方法调用结束后object对象没有被释放,一直到Simple结束才被释放。

解决方案:

    public class Simple {
        Object object;
        public void method1(){
            object = new Object();
            //...其他代码
            object=null    //增加一步
        }
    }

 5)尽早释放无用对象的引用。对于频繁申请内存和释放内存的操作,最好使用finalize强制执行或者自己写finalize方法,System.gc()方法不一定适用。在jvm垃圾收集器收集一个对象之前,一般要求程序员调用适当的方法释放资源,但在没有明确释放资源的情况下,java提供了默认机制终止化该对象来释放资源,即finalize()方法。

2.2 内存管理

java的内存管理就是对象的分配和释放问题。java中,程序员通过关键字new为每个对象申请内存(基本类型除外),所有对象都在堆中分配空间。对象释放由gc决定和执行。gc监控每一个对象的运行状态(申请、引用、被引用、赋值等)

内存泄露两个特点:1)对象可达,即存在通路与其相连2)对象是无用的。(内存泄露原因:1.全局集合。2.缓存3.ClassLoader)

2.3 clone

3.传递与引用

3.1传值和传引用

在java中,变量分为两类。(java传值传引用的讨论)

1)对于基本数据类型(int float long double boolean char byte),传值的副本。

2)对于一切对象型变量,java都是传引用的副本。传引用副本的实质就是复制指向地址的指针。(这点与C++不同,在c++中当参数是引用类型时,传递的是真实的引用而不是副本)

   String类型也是对象类型,所以它必然是传引用副本。它是非可变类,使用传值或者传引用 显得 没有区别。

对于基本类型而言,传值就是把自己复制一份传递,即使自己的副本变了自己也不会变。

对于对象类型,它传的是副本引用,指向自己的地址而不是实际值的副本。因为对象类型放在堆里,一方面速度相对于基本类型较慢,另一方面对象类型本身比较大,如果选择重新复制值浪费内存且速度慢。(有趣比喻:复制钥匙而不是复制仓库) ---说明,一些书籍如thinking in java提到“不管是基本类型还是对象类型,都是传值”他们是把引用副本也当做一种值。

 引用传递例子1:

 1 public class Test {
 2     public static void main(String[] args) {
 3         StringBuffer str= new StringBuffer("Hello");
 4         test(str);
 5         System.out.println(str);
 6     }
 7     public static void test(StringBuffer s){
 8         s=s.append(",World!");
 9     }
10 }

输出:Hello,World!

又一个例子2:

 1 public class Test {
 2     public static void main(String[] args) {
 3         String str= "Hello";
 4         test(str);
 5         System.out.println(str);
 6     }
 7     public static void test(String s){
 8         s="World!";  //系统自动生成一个新的String对象设为“World”,然后把这个对象的引用赋给str.
 9     }
10 }
输出:Hello

Stringl类是final类型的,因此不可以修改和继承这个类,当例子2中函数结束,s作用消失。

例子1中StringBuffer是产生一块内存空间,相关的增删改操作都在其中,仍然是在同一段内存地址上进行。

String StringBuffer Stringbuilder

1)可变、不可变

  String类中使用字符数组保存字符串,因为有“final”修饰符,所以可以知道string对象是不可变的。StringBuffer和Stringbuilder是可变的)

     ----String  -----private final char value[];

    -----StringBuffer和Stringbuilder  -----char[] value;

2)是否线程安全

  String中的对象是不可变的,也就可以理解为常量,显然线程安全

  AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。

  StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的

  StringBuilder并没有对方法进行加同步锁,所以是非线程安全的

  如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。

 同理,数组传值的本质也是传地址值的副本。

3.2. 静态变量与私有变量

定义在类里的变量会默认一个初始值。布尔类型默认初始值是false

main函数不能访问一个非静态变量或方法

3.3.输入/输出流

大文件读取:new BufferedReader(new InputStreamReader(new FileInputStream("filename")))

写入文件:FileOutputStream =new FileOutStream("filename") ;out.write("string to write".getBytes());out.close();

java IO操作有面向字节Byte和面向字符Character两种方式.

面向字节的操作以8位二进制为单位对数据操作,不需要对数据转化,这些操作的类都是InputStream和ouputStream的子类。

面向字符的操作以字符为单位读取时需要将二进制转化为字符,写的时候需要将字符转化为二进制,这些类都是Reader和Writer的子类。

3.4 序列化

3.5 HashMap和HashTable区别

Hashtable和HashMap有几个主要的不同:线程安全以及速度。

1)Hashtable是synchronized,HashMap是非synchronized.所以HashTable是线程安全的,HashMap是线程不安全的。因此如果是单线程,HashMap效率比HashTable高。

2)HashMap支持null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

3)HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

原文地址:https://www.cnblogs.com/xunyingFree/p/7368193.html