javaSE_3

来源:互联网 发布:unity3d 3dsmax 编辑:程序博客网 时间:2024/05/20 03:05

数据结构(对象容器):集合

习惯写法:        Collection  ee = new ArrayList() ;

 

 

java默认的equals== 效果是相同的,判断是不是引用相同的对象

Collections工具类提供了很多静态方法(基于List容器),操作集合

sort()  排序

shuffle()  对容器内的对象进行随机排列

fill()  用一个特定对象重写整个List容器

....

Arrays工具类提供   操作数组

 

Comparable接口

实现了compare接口的类通过实现comparaTo方法从而确定此类对象的排序方式

选择数据结构:

衡量标准:读的效率和改的效率

Array读快改慢

Linked改快读慢

Hash两者之间 效率很低,少用

 

 (传智版)

Collection的作用是存储数据,它的存储不是“持久化”的

(Deque)双端队列既是队列也是栈

Collection方法:

添加数据: add

删除数据: remove(Object o)

取出数据:

清空:clear()

判断是否包含指定的元素。contains(obj);

判断集合是否为空: isEmpty

获取集合里元素的数量:size()

 

--下面这些方法是集合与集合进行运算--  DEMO

addAll(Collection<? extends E> c)  集合的加法。

boolean removeAll(Collection<?> c)   集合的加法。

boolean retainAll(Collection<?> c)  集合的交集。

boolean containsAll(Collection<?> c)

 

Set

HashSet 存储机制是简单地说,一个萝卜一个坑。  HasCode决定其存放在位置

          HashSet的优势:存、取速度非常快。

          觉得HashSet性能高低的是loadfactor(负载因子),

          创建HashSet时,capacity越大,存取速度越快;

                capacity越大,内存开销就越大。  

DEMO  DEMO2  DEMO3

      负载因子的作用:控制HashSet满到什么程度,就应该重新分配更多的坑。

负载因子越大,空间利用率高,节省内存;存取速度可能会下降。

负载因子越小,存取速度相当快。内存开销大。

 

对于Set来说,当两个元素通过equals()比较返回true时,

Set会认为它们相等。

 

对于HashSet来说,一般要求其中的元素满足条件:

重写hashCodeequals方法:

  当两个元素的hashCode相同时,它们通过equals比较最好也返回true

 

TreeSet    DEMO

底层是红黑树实现。

TreeSet集合中元素是有序的,它的顺序是按照元素的大小排序的。

所以TreeSet要求集合中元素可以排序!否则就无法加到TreeSet中。

TreeSet有两种排序方式:

1. 自然排序。要求每个元素本身就是可比较大小的,它要求每个元素都实现Comparable接口。

2. 定制排序。由一个特定的对象来进行排序。特定的对象就是Compartor对象。

             它要求创建TreeSet时,指定一个排序器,也就是Compartor对象。

TreeSet : 它的性能比不上HashSet。通常来说,它没有HashSet快。

          它有一个好处:加入TreeSet中的元素总是处于有序状态(按大小排序)。

    

遍历数组的方法:

for (iterator <String > it = c2.iterator() ; it.hasNext())         //这个好像效率好低

增强的for 循环

 

List   DEMO

Collection多了一个功能,每个元对应的索引值,

ArrayList

它的底层其实就是一个数组,

可以创建ArrayList指定它的数组初始长度,默认长度是10

缺点:当添加的元素的超过了ArrayList底层数组长度时,会新创建一个数组(长度好像是原来 2倍),将老数组的元素复制到新数组中去,原来的被垃圾回收了,

在中间添删元素/时,群体搬家

优点:存取差不多相当于数组

 

linkedList

长度没有限制

 

遍历数组的接口:

Enumeration接口    早期版本,不用了

Iterator接口     

 

Map DEMO

Map中每个元素都是 key-value对,key-value当成一个整体

实际上Map在存储元素集合时,value是不考虑的,

如果我们只考虑map里的key,所有的key就组成了一个set  --keySet

所以keySet()返回所有key所组成的Set

存放key-value对时,只考虑key部分,不会考虑value部分,

所以HashMapkey的要求,与HashSet对集合元素的要求是一模一样的,

HashSet对集合元素的要求:

合理的重写equals  hashcode,如果两元素的HashCode相同,那么他们通过equals也应该是true

HashMap的元素也是有序的,按key来排序

 

SetMap的关系:

从逻辑上来看,Map相当于是key中所有元素都增加一个value附属物,

从底层实现来看,Set是用Map实现的,Set相当于value都是new ObjectMap

ListMap的关系:

可以把List当作 所有key值都是intMap

如果只看Map里的valueMapvalue会组成普通Collection集合

所以Map提供了values方法来返回所有的value所组成的Collection的集合

 

HashMap相似的有HashTable:

区别:

HashTable古老

HashTable性能不好,线程安全的

HashTable不允许键值对为null ,但HashMap允许

 

Set中集合具有:元素不能重复,无序的特征

Mapkey具有:key不能重复,无序的特征

 

HashCode作用:

高级 防止内存泄漏

 

 

(台湾版)

Stack接口                 后进先出(last-in,first-out,LIFO)

Queue接口                  先进先出(first in,first out,FIFO)   可认为是功能弱化的线性表(List

 

Iterator - Collection - List/Set/Map

List接口          类似于数组, 循环有索引的链表结构 DEMO  有顺序,可以重复  线性表

Set    接口                                          没有顺序,不能重复

Map 接口                          使用”键--值“(Key-Value)存取 不能有重复的键

 

Iterator接口      (所有实现Colleciton接口的容器都有一个iterator方法用以返回一个实现了Iterator接口的对象

iterator对象称作迭代器,用以方便的实现容器内元素的遍历操作)

for (iterator <String > it = c2.iterator() ; it.hasNext())

Iterable接口     

ListNode               链表结构

ArrayStack          

ArrayQueue

ArrayList            DEMO1  使用Iterator类改写DEMO1

ArrayIterator

LinkedStack

LinkedQueue

LinkedList  StringStack StringStackDemo  StringQueue  StringQueueDemo

ListIterator

HashSet                HashSet的排序规则是利用哈希法(Hash),所以加入HashSet容器的对象还必须重新定                                        hashCode()方法。HashSet根据哈希码来确定对象在容器中存储的位置,也可以根据                                            哈希码来快速地找到容器中的对象。

在先比较两个加入HashSet容器中的对象是否相同时,会先比较hashCode()方法返回的 值是否相同。如果相同,则再使用equals()方法比较,如果两者都相同,则视为相同的   对象。 HashSetDemo   LinkedHashMapDemo

 

TreeSetDemo  CustomComparator   TreeSetDemo2  

EnumSetDemo  EnumSetDemo2

 

HashMap    HashMapDemo  HashMapDemo2   LinkedHashSetDemo

TreeMapDemo  TreeMapDemo2

 

 

 

 

最常用集合框架: 总结   (清华版)

List结构的集合类

ArrayList类, 高级DEMO  加入相同的不会覆盖,但Map会覆盖的

LinkedList类,

Vector类,   (古老的类,但是线程安全的)

Stack

Map结构的集合类

HashMap类,HashTable [W1] 

Properties 类是Hashtalbe的子类

增加了将Hashtable对象中的关键字和值保存到文件和从文件中读取关键字和值到Hashtable对象中的方法;如果要Properties.store方法存储Properties对象中的内容,每个属性的关键字和值都必须是String类型

DEMO 使用Properties把程序的启动运行次数记录在某个文件中,每次运行时打印出它的运行次数

Set结构的集合类

HashSet类,TreeSet

Queue结构的集合类

Queue接口

HashMap hm = new HashMap();

可以写成

Map hm = new HashMap();

Vector类与Enumeration接口

Collection接口与Iterator接口

CollectionSetList的区别

SetList Collection接口的子类

Collection各元素对象之间没有指定的顺序,允许有重复元素的多个null元素对象

Set各元素对象之间没有指定的顺序,不允许有重复元素,最多允许有一个null元素对象

List各元素对象对象之间指定顺序,允许有重复元素和多个null元素对象

 

 

 

基本数据类型 要转换成包装类才能add到集合类中去 (好像5.0后会自动转换)

基本数据类型

包装类

boolean

Boolean

byte

Byte

char

Character

short

Short

int

Integer

long

Long

float

Float

double

Double

 


HashMapHashtable的都是java的集合类,都可以用来存放java对象,但他们也有区别:

1.历史原因Hashtable基于陈旧的Dictionary类,HashMapjava1.2引进的Map接口的一个实现。

2.同步性Hashtable是线程同步的。保证了线程安全。而HashMap则是异步的,并不是线程安全,但速度会变慢。

3.可以让你将空值作为一个表的条目的keyvalue但是Hashtable是不能放入空值(null)

HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。

  Hashtable 类似于 HashMap,但是不允许 null 键和 null 值。它也比 HashMap 慢,因为它是同步的。

 

并发性(线程)

       同一时刻只能有一个指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果

并行性(进程)

       同一时刻,有多条指令在多个处理器上同时执行

线程开销小,可以共享内存,线程之间进程数据交换比较容易

多线程 Thread

 

wait():使一个线程处于等待状态,并且释放所持有的对象的lock

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

 

Thread子类对象的start(从Thread类继承到的)方法,而此start方法将产生一个新的线程,并在此线程上运行此Thread类对象中的run方法。根据运行对象时的多态性,在此线程上实际运行的的是Thread子类(也就是我们写的那个类)对象中的run方法

前台线程

后台线程  setDaemon(true);  (如果只有后台线程在运行,没有前台线程的话,全部线程就会结束)

         当你需要把一条线程设为后台线程,必须先设置,再启动。

 

 

extends Thread创建一个TestThread线程类

TestThread tt = new TestThread();

tt.start();

tt.start();

...

只是产生一个线程

 

new TestThread().start();

new TestThread().start();

new TestThread().start();

产生3个线程

 

implements Runnable 创建一个TestThread线程类

TestThread tt = new TestThread();

new Thread(tt).start();

new Thread(tt).start();

new Thread(tt).start();

产生3个线程

 

try{Thread.sleep(1);} catch(Exception e){}

//线程停1毫秒

 

线程安全:  synchronized(str ) {}

线程的同步是按照某一对象的标识位,,

 

同步代码块,同步方法 区别

同步方法使用的同步监视对象是this,如果要让同步代码块,同步方法同步,同步代码块就用this作为同步监视对象。

 

 

线程优先级: DEMO

线程的优先级用1-10之间的整数表示,数值越大优先级越高,默认的优先级为5

可用getPriority()方法读取一个线程的优先级,并用setPriority()改变它。

运行该程序时,我们可注意到几件事情。首先,线程组的默认优先级是5。即使在启动线程之前(或者在创建线程之前,这要求对代码进行适当的修改)将最大优先 级降到5以下,每个线程都会有一个5的默认优先级。

试着提高组的最大优先级。可以发现,这样做是没有效果的。我们只能减少线程组的最大优先级,而不能增大它。    setPriority( Thread. NORM_PRIORITY + 2 ))    NORM_PRIORITY相当于5

 

c#线程优先级:

线程优先级:       DEMO

线程的优先级可以定义为ThreadPriority枚举的值,即HighestAboveNormalNormalBelowNormal Lowest

 

 

创建线程的两个方式:  三种方式

继承java.lang.Thread

EraserThread  EraserThreadDemo

实现java.lang.  Runnable接口  灵活  (线程安全)

Eraser  EraserDemo 基本上建议用此方式让对象具有纯程功能,保留日后修改的弹性

this.active = active;

前面两种种方式的线程执行体(也就是run方法)不能声明抛出异常也不能有返回值

第三种方法:实现Callable接口(它是Runnable的增强版)。  DEMO 好处是得到返回值

      实现call()run()的增强版)方法,call()方法就是线程执行流。

    a. 创建Callable实现类的对象。

    b. Callable实现类的对象包装FutureTask,它代表了call()方法的返回值将来才会返回。

    c. FutureTask的对象作为target参数,创建Thread对象

    d. 调用Thread对象的start()方法来启动它。

         //调用FutureTaskget()方法时要小心!

 

千万不要直接调用线程执行体的方法!既不要调用run方法,也不要调用call方法。

 

实现RannableCallable本质上是相同的

 

Daemon线程        主线程结束后,Daemon线程就会跟着结束  DaemonThread

线程生命周期       创建线程(new Thread)、就绪(Runnable)、堵塞(Blocked)、消亡(Dead)

 

如果想让目前线程礼让一下其他线程,让它们有机会获得执行权,可以调用yield()方法[W1] 

使用isAlive()方法来测试线程是否存活。

 

有几种状况会让线程进入Blocked状态:

等待输入输出完成

调用sleep()方法

尝试获得对象锁定

调用wait()方法

Thread类的静态方法:

currentThread():获取当前正在执行的线程。

sleep(n):让当前正在执行的线程暂停n ms,当前线程将会进入阻塞状态。

yield():让当前正在执行的线程暂停,它只是让当前线程进入就绪状态。

         yield方法是给那些比当前线程优先级高、相等的线程一个执行的机会。

 

以下几个情况让线程回到Runnable状态:

输入输出完成

调用interrupt()  InterruptDemo

获得对象锁定

调用notify()notifyAll() [W2]   Clerk  Consumer  Producer      ProductTest

 

线程的加入(join)

当线程使用join()加入至另一个线程时,另一个线程会等待这个被加入的线程工作完毕,然后再继续它         的动作       ThreadA (变成单线程)

yield()  让出CPU

 

线程的停止    //让线程停止 最好用这种方法   DEMO

Threadstop()方法已经被标示为deprecated,不建议使用stop()来停止一个线程的运行。

如果想要停止一个线程,最好自行实现。一个线程要进入Dead状态,就是执行完run()方法,简单地  说,如果您想要停止一个线程的执行,就要提供一个方式让线程可以完成run()的流程,而这也是自行   实现线程停止的基本概念。

如果线程的run()方法中执行的是一个重复执行的循环,可以提供一个标志(flag)来控制循环是否执行,         从而让循环有机会终止,使线程可以离开run()方法以终止线程:  DEMO

 

如果线程因为执行sleep()而进入Blocked状态,而您想要停止它,可以使用interrupt(),而程序会抛出  InterruptedException异常,因而使得线程离开run()方法        SomeThread

 

如果程序因为等待输入输出设备而停滞(进入Blocked状态),比如说引发一 个异常,而这个异常要如何        引发,要看所使用的输入输出而定。

例如您使用readLine()等待网络上的一个信息,此时线程进入Blocked直到读到一个信息,您要让         它离开run()的方法就是使用close()关闭它 的字符串流,这时会引发一个IOException异常而使得线程 离开run()方法,例如:

上面这个程序是个简单的架构示范,实际的设计必须视您的程序功能与I/O类型而定。除了stop()        之外,suspend()resume()方法也被标示为deprecated,如果要达成与这些方法相同的功能,都必        须自行设计。

线程组(ThreadGroup)

Thread.currentThread().getThreadGroup().getName();        [W3] 

可以自行指定线程组,线程一旦归入某个组,就无法更换组。

 

ThreadGroup threadGroup1 = new ThreadGroup("group1");
ThreadGroup threadGroup2 = new ThreadGroup("group2");
Thread thread1 =
new Thread(threadGroup1, "group1's member");
Thread thread2 =
new Thread(threadGroup2, "group2's member");

 

ThreadGroup中的某些方法,可以对所有的线程产生作用,例如interrupt()方法可以interrupt线程组中所有的线程,setMaxPriority()方法可以设置线程组中线程所能拥有的最高优先权(本来就拥有更高优先权的线程不受影响)

如果您想要一次获得线程组中所有的线程来进行某种操作,可以使用enumerate()方法,例如:

Thread[] threads = new Thread[threadGroup1.activeCount()];
threadGroup1.enumerate(threads);

activeCount()方法获得线程组中正在运行的线程数量,enumerate()方法要传入一个Thread数组,它将线          程对象设置到每个数组字段中,然后就可以通过数组索引来操作这些线程。

 

ThreadGroup中有一个uncaughtException()方法。当线程组中某个线程发生Unchecked exception异常时,       由执行环境调用此方法进行相关处理,如果有必要,您可以重新定义此方法,直接使用范例15.9来示      范如何实现。

 

线程池()  JDK 15之前要手动实现,  Executors工厂类

线程池在系统启动时即创建大量空闲的线程

程序将一个Runable对象传入线程池,线程池就会启动一条线程来执行此对象的run方法,当run方法执行结束后,此线程并不会死亡,而是再次回到线程池中成为空闲状态,等待执行下一个Runnable对象的run方法。

除此之外,使用线程池可以有效地控制系统中并发线程的数量,当系统中包含大量并发线程时,会导致系统性能急剧下降,甚至JVM崩溃,而线程池的最大线程的最大线程数参数可以控制系统中并发线程数目不超过过此数目。

//创建一个具有固定线程数的线程池

ExecutorService pool = Executors.newFixedThreadPool(6) ;

//向线程中提交线程    这时线程已经在执行了。

Pool.sumit(new TestThread()) ;

//关闭线程池

Pool.shutdown() ;

UncaughtExceptionHandler

J2SE 5.0之前,如果要统一处理某些线程的Unchecked Exception,可以使用ThreadGroup来管理。  在继承ThreadGroup之后重新定义其uncaughtException()方法,就如范例15.9所示。在J2SE 5.0之后,       就不用这么麻烦,可以让异常处理类使用Thread.UncaughtExceptionHandler接口,并实现                uncaughtException()方法

ThreadExceptionHandler   ThreadGroupDemo2

同步化(synchronized)

synchronized关键词可用于方法上,让方法所包括的范围(Scope)内都成为同步区域,

使其在同一时间只能有一个线程访问 例如:

public synchronized void setNameAndID(String name, String id) {this.name = name;this.id = id;if(!checkNameAndIDEqual()) {System.out.println(count +") illegal name or ID.....");}count++;}

synchronized的设置不仅可用于方法上,也可以用于限定某个程序区块为同步区域,例如:

public void setNameAndID(String name, String id) {synchronized(this) {this.name = name;this.id = id;if(!checkNameAndIDEqual()) {System.out.println(count +") illegal name or ID.....");}count++;}}

也可以标识某个对象要求同步化。

 

// arraylist参考至一个ArrayList的一个实例

synchronized(arraylist)

{

arraylist.add(new SomeClass());

}

 

同步代码块: 需要显式指定同步监视器。

同步方法:   不需要显式指定同步监视器。

             当方法是实例方法时,同步监视器是this

             当方法是静态方法时,同步监视器是当前类。

 

用了synchorozied 之后,会导致性能下降。

synchorozied 时要小心,它所控制的代码块应该尽量小!

synchorozied 应该恰好只控制修改共享资源的代码块。

 

 

DEMO  synchronized(this)  当调用此方法时,锁定当前对象

死锁  DEMO 

 

生产者消费者模式 DEMO

模式运用到线程间通信

DMEO 不太准确

推荐用这种方法 更加简单的,把同步代码放到同一个类中 DEMO

Synchronized

 

 

区别太大

wait  (object对象的方法)  (wait 锁就不归原来所有了)

         Wait时别的线程可以访问锁定的对象

         调用wait方法时必需锁定此对象

sleep (Thread对象的方法)

         sleep时别的对象不可以访问锁定对象

 

notify 叫醒一个在我这个对象上wait的对象,让它继续执行

notify/notifyAll

 

沿学版 生产者消费者问题 ProducerConsumer.java

 


 

yield()方法让同样优先权的线程有被执行的机会,当线程执行yield()方法让出执行权时,它会再度处于Runnable状态,等待调度。对于支持Timeslicing的操作系统,不需要调用yield()方法,因为操作系统会自动分配时间给线程来轮流执行。

 

如果您要暂停线程,但暂停的时间未知,使用sleep()并不是个好方法,您可以使用wait()让线程进入Blocked状态,

然后让别的线程用notify()notifyAll()来通知被Blocked的线程回到Runnable状态

 

通过wait()方法您可以要求线程进入对象的等待池(Wait Pool),或是通知线程回到锁定池的Blocked状态。

 

必须在同步的方法或区块中才能调用wait()方法(也就是线程获得锁定时)。当对象的wait()方法被调用,目前的线程会被放入对象的等待池中,线程归还对象的锁定,其他的线程可竞争对象的锁定;被放在等待池中的线程也是处于Blocked状态,所以不参与线程的调度。

 

wait()可以指定等待的时间。如果指定时间的话,则时间到了之后,线程会再度回到锁定池的Blocked状态,等待竞争对象锁定的机会,如果指定时间为0或不指定,则线程会持续等待,直到被中断(interrupt),或是被告知(notify)回到锁定池的Blocked状态

 

获得目前线程所属的线程组名称:

 

线程间的通信 java所有对象都有这些方法

wait:告诉当前线程放弃监视器并进入睡眠状态直到其他线程进入同一个监视器并调用notify为止

notify:唤醒同一对象监视器中调用wait的第一个线程。用于类似饭馆有一个空位后通知所有等候就餐的顾客中的第一位可以入座的情况

notify All:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类似某个培训班终于招满人,通知所有学员都来上课的情况

 

容器类的线程安全(Thread-safe)

容器类默认没有考虑线程安全问题,您必须自行实现同步以确保共享数据在多线程存取下不会出错。例如,若您使用 List对象时,可以这样实现:

// arraylist参考至一个ArrayList的一个范例
synchronized(arraylist) {
arraylist.add(new SomeClass());
}

事实上,您也可以使用java.util.CollectionssynchronizedXXX()等方法来传回一个同步化的容器对象,例如传回一个同步化的List

List list = Collections.synchronizedList(new ArrayList());

以这种方式返回的List对象,在存取数据时会进行同步化的工作。不过在您使用Iterator遍访对象时,仍必须实现同步化,因为这样的List使用iterator()方法返回的Iterator对象,并没有保证线程安全(Thread-safe),一个实现遍历的例子如下:

List list = Collections.synchronizedList(new ArrayList());
...
synchronized(list) {
Iterator i = list.iterator();
while (i.hasNext()) {
foo(i.next());
}
}

 

J2SE 5.0之后,新增了一个package,即java.util.concurrent。其中包括了一些确保线程安全的Collection类,例如ConcurrentHashMapCopyOnWriteArrayListCopyOnWriteArraySet等。这些新增的 Collection 类的基本操作与先前介绍的MapListSet等对象是相同的,所不同的是增加了同步化的功能,而且依对象存取时的需求不同而有不同的同步化实现,以同时确保效率与安全性。

例如,ConcurrentHashMap针对Hash Table中不同的区段(Segment)进行同步化,而不是对整个对象进行同步化。ConcurrentHashMap默认有16个区段,当有线程存取第一个区段时,第一个区段进入同步化,然而另一个线程仍可以存取第一个区段以外的其他区段,而不用等待第一个线程存取完成,所以与同步化整个对象来说,新增的ConcurrentHashMapCopyOnWriteArrayListCopyOnWriteArraySet等类,在效率与安全性上获得了较好的平衡。

Vector

Hashtable

---------------------------------

即使我们需要使用线程安全的集合,也没必要使用VectorHashtable

我们可以另一个工具类:Collections

它里面提供了系列的 synchronizedXxx,它用于将原有的集合包装成线程安全的集合。

HashMap map = new HashMap(); //线程不安全的。

HashMap map = Collections.synchronizedMap(new HashMap()); //线程安全的。

 

 

 

ThreadLocal

http://book.51cto.com/art/200812/103988.htm

ThreadLocal

为每个线程创造一个资源的复本。将每一个线程存取数据的行为加以隔离,实现的方法就是给予每个线程一个特定空间来保管该线程所独享的资源

concurrent套件新增类

BlockingQueue

http://book.51cto.com/art/200812/103989.htm

CallableFuture

http://book.51cto.com/art/200812/103994.htm

Executors

http://book.51cto.com/art/200812/103995.htm

 

 

(疯狂JAVA版)

JVM进程的结束:

1. 程序运行完成。

2. 程序执行System.exit(); Runtime.getRuntime().exit()

3. 遇到未捕获的异常。

4. 所在平台(操作系统)强行结束进程。

 

类加载:

类加载:指的是将该类对应.class文件(通常在磁盘、可能直接在内存中、可能来自于网络)

        读入内存,并创建对应的Class对象。

1. 加载。将二进制文件(class文件,通常在磁盘上)读入内存。

2. 连接。为类生成对应的Class对象(堆内存的permanent代中),并将它存入JVM中。[W1] 

3. 初始化。对静态属性进行初始化,并调用静态初始化块对类执行初始化。[W2] 

(对于一个final型的静态属性,如果此属性可以在编译时就得到属性值,则可认为此属性可被当居编译时常量。当程序使用编译时常量时,系统会认为这是对此类的被动使用,所以不会导致此类的初始化)DEMO

(当使用classLoader类的loadClass()方法来加载某个类时,此方法只是加载此类,并不会执行此类的初始化。当使用ClassforName()静态方法的才会导致强制[初始化此类)

 

String

Java中所有的类,都是Class对象。

所有类、每个类 有个对应Class对象,它就在内存的Permanent

所有类的加载都由一个叫 ClassLoader的东西来完成。

 

类加载机制:

3大特征:

全盘负责:当一个类加载器去加载某个类,该类加载器将会同时加载与之关联的所有的类。

父类委托:当你要加载某个类时,总是先让父类加载器尝试加载; (委托机制)

          只有当父类加载器无法加载该类时,才会由子类加载器去加载。

缓存机制:一个类被加载之后,将一直缓存在堆内存permanent代中。

 

Java的类加载器:  DEMO [W3]   类加载器也是一个JAVA

大部分时候,系统提供了4个类加载器。

   根加载器 (在程序中一般不需要访问     jre/lib/rt.jar)

     

 扩展类加载器 (会负责加载JDK系统的类库   jre/lib/ext/*.jar

     

 系统类加载器 (该类加载器会负责加载CLASSPATH中的class文件。它会负责加载程序员写的类)

     

 用户类加载器

 

private(类访问) <default>(包访问)→ protected(子类访问)→ public(全局)

 

自定义类加载器的方法: DEMO   

1. 继承ClassLoader抽象类。

2. 重写关键方法findClass即可。

    findClass(String name)

    loadClass(String name)

    核心方法

    defineClass(String name, byte[] b, int off, int len):通常不应该考虑重写该方法。

       b数组中,从off位置开始、长度为len的字节内容转换为Class对象。

   一般考虑重写findClass方法。

 

通过反射查看类信息:

如何获取类对应的Class对象。(字节码)

  调用Class.forName(类名字符串);    Class qq =  Class.forName("org.crazyit.test.Hello")

  调用指定类的class属性。   Class qq =  org.crazyit.test.Hello.class

  调用指定对象的getClass()方法。  Class qq = "aasas".getClass()

 

一个虚拟机,对于一个类,最多只初始化一次。

一个类,在一个虚拟机里,最多只有一个对应的Class对象。

 

确定一个方法需要3个方面。

1 哪个类。 Class对象确定。

2 方法名 

3 形参列表

 

确定一个构造器需要2个方面:

1. 哪个类   Class对象确定。

2. 形参列表。

 

确定一个Field需要2个方面:

1. 哪个类   Class对象确定。

2. Field名字

 

Class对象的方法:   DEMO

  getConstructor/getConstructors 用于获取构造器。

  getMethod/getMethods用于获取方法。

  getField/getFields用于获取属性。

  getSuperclass获取父类

  getInterfaces获取所实现的接口。

 

Class对象的作用:用于获取类内部的其他成分(方法、构造器、field  DEMO

获取了Constructor,可用于产生对象。

获取了Method之后,可以调用方法。

获取了Field之后,可以访问、或者修改它的值。

 

反射会导致 程序性能下降

Field  成员变量的类

Method

使用BeanUtils工具包

利用到logging工具包

 

反射就是加载类《〈 解剖出类的信息

java里有一个Class类,代表某个类的字节码

Class.forName()

类名.class()

对象.getClass()

 

Class对象提供了如下常用方法:

Public  Constructor  getConstructor(Class<?>... parameterTypes)

Public  Method  getMethod(String name, Class<?>... parameterTypes)

Public  Field  getField(String name)   public

 

public Constructor getDeclaredConstructor(Class... parameterTypes)

public Method getDeclaredMethod(String name,Class... parameterTypes)

public Field getDeclaredField(String name)    

 

//反射类无参的构造方法

Class clazz = Class.forName("cn.itcast.reflect.Person");

                   Constructor c = clazz.getConstructor(null);

                   Object obj = c.newInstance(null);

                   System.out.println(obj);

//反射类有参的构造方法:public Person(String name)

Class clazz = Class.forName("cn.itcast.reflect.Person");

                   Constructor c = clazz.getConstructor(String.class);

                   Person p = (Person) c.newInstance("flx");

                   System.out.println(p);

 

私有成员外界不能访问,,但反射可以做到

 

//反射类私有的、有参的构造方法:private Person(int name)

Class clazz = Class.forName("cn.itcast.reflect.Person");

                   Constructor c = clazz.getDeclaredConstructor(int.class);

                   c.setAccessible(true);//暴力反射

                   Person p = (Person) c.newInstance(1);

                   System.out.println(p);

 

利用Method执行方法:

jdk1.4jdk1.5invoke方法的区别:

Jdk1.5public Object invoke(Object obj,Object... args)

Jdk1.4public Object invoke(Object obj,Object[] args)

 

利用Field访问属性

public void set(Object obj,Object value)

public Object get(Object obj)

 

利用反射做框架:

BufferedReader br = new BufferedReader(new FileReader("src/config.txt"));

                   String className = br.readLine();

                   String methodName = br.readLine();

                  

                   Class clazz = Class.forName(className);

                   Method method = clazz.getMethod(methodName, null);

                   method.invoke(clazz.newInstance(), null)

 

内省(Introspector)

开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性。

private String name ;                  //这时仅仅是一个字段

如果nameget set方法,name才算是一个属性

PropertyDescriptor pd = new PropertyDescriptor("name",Student.class);

                   Method method = pd.getWriteMethod();  //setName()

                   method.invoke(s, "flx");

                   //System.out.println(s.getName());

                   method = pd.getReadMethod();   // getName

                   String result = (String) method.invoke(s, null);

                   System.out.println(result);

 

通过PropertyDescriptor类操作Bean的属性

通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。

 

//操作bean的所有属性

BeanInfo info = Introspector.getBeanInfo(Student.class);

                   PropertyDescriptor pds[] = info.getPropertyDescriptors();

                   for(PropertyDescriptor pd : pds){

                            System.out.println(pd.getName());

                   }

beanutils工具包

Beanutils工具包的常用类:

BeanUtils          BeanUtils.setProperty(s, "name", name);

PropertyUtils

ConvertUtils.regsiter(Converter convert, Class clazz)         类型转换器

自定义转换器

 


类连接:

验证

准备:为类的静态属性分配内存空间,并设置默认值。

解析:将类的二进制数据的符号直接替换。

(连接阶段将会负责把类的二进制数据合并到JRE)

当初始化某个烦扰子类时,此子类的所有父类都会被初始化

根类加载器并没有继承ClassLoader抽象类,所以扩展类加载器的getParent()方法返回null,但实际上根加载器确实是扩展类加载器的父类加载器

射:(台湾版) (内省 IntroSpector)

可以通过ObjectgetClass()方法来取得每个对象对应的class对象..ClassDemo

也可以使用以下方法取得String类的Class类对象

Class stringClass = String.class

声明参考名称并不会加载类,而使用new生成对象时才会加载类 TestClass  LoadClassTest

数组也是一个对象,也有其对应的Class实例     ClassDemo2

类加载后,JVM就会自动为其生成一个Class对象

 

使用Class.forName()加载类

ForNameDemo

forNamer的第二个版本,指是否运行静态区块,指定类加载器

TestClass2  ForNameDemoV1    ForNameDemoV2

 

Class中获取信息

Class对象表示所加载的类,取得Class对象之后,就可以取得与类相关联的信息,     像包、构   造函数、方法成员等,而每一个信息也会有相应的类类型。

例如的对应类型是java.lang.Package     ClassInfoDemo

构造函数的对应类型是java.lang.reflect.Constructor       SimpleClassViewer

方法成员的对应类型是java.lang.reflect.Method      InvokeMethodDemo

域成员的对应类型是java.lang.reflect.Field

 

类加载器

类加载器以java.lang.classLoader类型存在

合作行执行java xxx.class指令后,java运行程序会找到JRE安装的所在目录,然后寻找jvm.dll    (默认在JRE目录下的bin/clint目录下),接着启动JVM并进行初始化动作,产生Bootstarp Loader         Bootstarp Loader会加载Extended Loader,并设置Extended LoaderparentBootstarp Loader         Bootstarp Loader会加载System Loader,并将System Loadeparent设置为Bootstarp Loader[W1] 

最后System Loader开始加载指定的类。在加载类时,每个类加载器会先将加载类的任务交给其  parent,如果parent找不到,再由自己负责加载。

所以会以Bootstarp Loader -- Extended Loader -- System Loader 的顺序来寻找类,都找不到就会传  NoClassDefFoundError

 

Bootstarp Loader会搜索系统参数sun.boot.class.path中指定位置的类,默认是JRE所在目录  classes下的.class文件或lib目录下的.jar文件中(如rt.jar)的类并加载。

可以使用System.getProperty("sun.boot.class.path")语句来显示指定的路径

Extended Loader会搜索系统参数java.ext.dirs中指定位置的类,默认是JRE目录下的    lib/ext/classes目录下的.class文件lib目录下的.jar文件中(如rt.jar)的类并加载。

可以使用System.getProperty("java.ext.dirs")语句来显示指定的路径

System Loader会搜索系统参数java.class.path中指定位置的类,也就是classpath所指定的     路径。      

可以使用System.getProperty("java.class.path")语句来显示指定的路径

在使用java运行程序时,也可以加上-cp来覆盖原有的Classpath设置

Java -cp ./classes someclass

 

每个类被加载后都会有一个class的实例来代表,而每个Class的实例都会记得自己是由哪个        ClassLoader加载的。

可以由classgetClassLoader()取得加载此类的ClassLoader,而从ClassLoadergetParent()      法可以取得自己的parent         DEMO

[W2] (下面这个有点复杂,必要时是不用理的)

getParent()

getParent()

getClassLoader()

getClass()

Bootstrap Loader

ExtClassLoader

AppClassLoader

Class someclass

实例 someclass

 

 

 

 

 

 

 

 

 

 

 


 

取得ClassLoader的实例之后,可以使用它的LoadClass来加载类。

使用LoadClass加载类时,不会运行静态区块     ForNameDemoV3

 

ExtClassLoaderAppClassLoader都是java.net.URLClassLoader的子类,可以在使用java启动      程序时,使用以下指令来指定ExtClassLoader的搜索路径:

Java -Djava.ext.dirs=c:/workspace/YourClass

使用-classpath-cp来指定AppClassLoader的搜索路径,也就是设置Classpath[W3] 

Java -classpath c:/workspace/YourClass

 

 

使用自己的ClassLoader

打算动态地从其他路径加载类,就要产生新的类加载器

在新增了ClassLoader实例后,可以使用它的loadClass()方法来指定要加载的类名称。

在新增ClassLoader时,会自动将新建的ClassLoaderparent设置为AppClassLoader,并在每     次加载时,先委托parent代为搜索。所以上例搜索someclass类时,会一直往上委托至Bootstrap         Loader开始搜索,接着是ExtClassLoaderAppClassLoader。如果都找不到,才使用新建的    ClassLoader搜索

所以,java的类加载层次架构:动态加载类,安全

 

由同一个ClassLoader加载的类文件,会只有一份Class实例。如果同一个类文件由两个不       ClassLoader载入,则会有两个不同的class实例。

注意,如果有两个不同的ClassLoader搜索同一个类,而在parentAppClassLoader搜索路径中可以找到指定类,则CLass实例就只会有一个,因为两个不同的ClassLoader都是在委托父ClassLoader时找到此类的。如果父ClassLoader找不到,而是由各自的ClassLoader搜索到,则class的实例会有两份                 ClassLoaderDemo

 

 

使用反射机制生成与操作对象:

使用反射机制可以在运行时期,动态加载类并生成对象,操作对象上的方法,改变类成员的值,甚至连私有成员的值也可以改变。

生成对象:

newInstance()实例化一个对象,实例化的对象以Object类型返回           NewInstanceDemo

 

调用方法:

调用student类的setName方法InvokeMethodDemo

 

修改成员值:

TestField   AssignFieldDemo

 

数组对象      ArrayDemo    NewArrayDemo    NewArrayDemo2

 

Proxy对象   

要在类中的一个方法的调用前后加上记录的功能,但又不会将记录的功能写到类中,使用Proxy类来实现动态代理

使用Proxy.newProxyInstance()建立一个代理对象,建立对象时必须告知所要代理的接口,然后可以操作所建立的代理对象,在每次操作时会调用InvocationHandlerinvoke()方法

IHello         HelloSpeaker       LogHandler         ProxyDemo

 

 

javadoc注释:

javadoc 标记由“@”及其后所跟的标记类型和专用注释引用组成
javadoc
标记有如下一些:
@author
标明开发该类模块的作者
@version
标明该类模块的版本
@see
参考转向,也就是相关主题
@param
对方法中某参数的说明
@return
对方法返回值的说明
@exception
对方法可能抛出的异常进行说明

@author
作者名
@version
版本号
其中,@author 可以多次使用,以指明多个作者,生成的文档中每个作者之间使用逗号 (,) 隔开。@version 也可以使用多次,只有第一次有效

使用 @param@return @exception 说明方法
这三个标记都是只用于方法的。@param 描述方法的参数,@return 描述方法的返回值,@exception 描述方法可能抛出的异常。它们的句法如下:
@param
参数名 参数说明
@return
返回值说明
@exception
异常类名 说明

 

javadoc -d doc -subpackages com.liigo

其中 com.liigo 是主包最终生成的API文档位于 c:/src/doc 目录

Annotation 注释 注解

可以在包、类、方法、域成员等加上Annotation

@Override          必须是重写父类中的同名方法    CustomClass       CustomClass2

@Deprecated       使用一段时间后,不建议开发人员使用       Something  SomethingDemo

@SuppressWarnings    忽略本来的警告信息           SomeClass          SomeClass2

 

自定义Annotation类型:

UnitTest         FunctionTest          UnitTest2       

Process           Application           

 

Meta-annotation

告诉编译器如何处理 annotation @Retention

在使用Retention类型时,需要提供 java.lang.annotation.RetentionPolicy的枚举类型

Package java.lang.annotation;

Public enum RetentionPolicy{

SOURCE,  //编译器处理完annotation 信息后就没事

CLASS,     //编译器将annotation 存储于CLass文件中,默认

RUNTIME                   //编译器将annotation 存储于CLass文件中,可由VM读入

}

SomeAnnotation           SomeClass3        AnalysisApp

限定annotation 使用对象@Target

在定义Annotation类型时,使用java.lang.annotation.Target可以定义其适用的时机。在定义时要指定要  指定java.lang.annotation.ElementType的枚举值之一:

Package java.lang.annotation;

Public enum ElementType{

TYPE,        //适用class,interface,enum

FIELD,      //适用field

METHOD,                   //适用method

PARAMETER,   //适用method上之parameter

CONSTRUCTOR,       //适用constructor

COCAL_VARIABLE, //适用区域变量

ANNOTATION_TYPE,       //适用annotation类型

PACKAGE                            //适用package

}

MethodAnnotation

要求为API文件的一部分@Documented              TwoAnnotation

继承父类的annotation  @Inherited                       ThreeAnnotation

默认父类中的Annotation并不会被继承至子类中。可以定义Annotation类型时加上      java.lang.annotation.Inherited类型的Annotation,继承保留于子类中。

 

日志(Logging): 使用Logging工具类

LoggingDemo    

Logging的等级:LoggingLevelDemo

Logger默认的处理者是(Handler)是java.util.logging.ConsolerHander,也就是将信息输出至命令模式。一个          Logger可以有多个处理者,每个处理者可以有自己的信息等级,在通过Logger的等级限制后,实际上还要 再经过处理者的等级限制。要看到所有的信息,如:LoggingLevelDemo2    另一种写法LoggingLevelDemo3

 

HandlerFormatter

Logger默认的输入处理者是ConsolerHanlerConsolerHanler的输出是使用System.err对象,而信息的  默认等级是INFO,这可以在JRE安装目录下lib目录的logging.properties中看到:

Handlers = java.util.logging.consoleHandler

java.util.logging.ConsoleHandler.level = INFO

 

Java提供了五个默认的Handler

java.util.logging.ConsoleHandler    System.err输出日志

Java.util.logging.FileHandler 将信息输出至文件     HandlerDemo

Java.util.logging.StreamHandler     以指定的OutputStream实例输出日志

Java.util.logging.SocketHandler      将信息通过Socket传送至远程主机

Java.util.logging.MemoryHandler 将信息暂存在内存中

 

自定义Formatter格式:

FilHandler默认输出格式是XML格式,输出格式由java.util.logging.Formatter来控制。例如FilHandler   的默认格式是java.util.logging.XMLFormatter,而ConsoleHandler的默认格式是  java.util.logging.SimpleFormatter。可以使用Handler实例的setFormatter()方法来设置信息的输出格式。

例如:       fileHandler.setFormatter(new SimpleFormatter());

TableFormatter              TableFormatterDemo

 

Logger层次关系:       LoggerHierarchyDemo

 

信息绑定:更改文字信息时,只要更改文本文件的内容而不用重新编译程序

使用ResourceBundle

Messages   ResourceBundleDemo

 

格式化信息:

messages2  MessageFormatDemo

 

国际化信息:messages3_zh_cn  I18NDemo

 

 

JDBC入门:   CRUD Create(创建)、Read(读取)、Update(更新)和Delete(删除)

JDBC数据库驱动程序按实现方式可以分为4个类型:

Type 1JDBC-ODBC Bridge

Type 2Native-API Bridge

Type 3JDBC-middleware

Type 4Pure Java Driver

连接数据库

加载JDBC驱动程序 [W4] 

提供JDBC URL

协定:子协定:数据源识别

jdbc:mysql://主机名称:连接端口/数据库名称?参数=&参数=

jdbc:mysql://localhost:3306/demo?user=root&password=123

如果要使用中文存取的话,还必须给定参数useUnicodecharacterEncoding,表明是否使用Unicode,并指定字符编码方式,例如:

jdbc:mysql://localhost:3306/demo?user=root&password=123&useUnicode=true&characterEncoding=Big5

 

获得Connection对象之后,可以使用isClosed()方法测试与数据库的连接是否关闭,在操作完数据库之后,如果确定不再需要连接,则必须使用close()来关闭与数据库的连接,以释放连接时相关的必要资源。

 

 

简单的Connection工具类

先设计一个DBSource接口,规范获得Connection的方法    DBSource

实现DBSource接口,您的目的是从属性文件中读取设置信息、加载JDBC驱动程序   SimpleDBSource

使用一个简单的程序来测试SimpleDBSource       ConnectionDemo

 


Bootstarp Loader通常是由C编写而成的,

Extended Loader是由JAVA编写而成的,实际对应于sun.misc.Launcher$ExtClassLoader(Launcher中的内部类)

System Loader是由JAVA编写,实际对应于sun.misc.Launcher$AppClassLoaderLauncher中的内部类)

AppClassLoader

就是System Loader

会覆盖原有的classpath定义

JDBC4.0以后,不需要再调用forName()加载了,系统会自动搜索

原创粉丝点击