---------------------- android培训、java培训、期待与您交流! ----------------------
泛型(Generic) jdk1.5新特性枚举挺多的练习也多今天好多时间都花在枚举上了
lJDK5以前,对象保存到集合中就会失去其特性,取出时通常要程序员手工进行类型的强制转换,这样不可避免就会引发程序的一些安全性问题。例如:
ArrayList list = new ArrayList();
list.add("abc");
Integer num = (Integer) list.get(0); //运行时会出错,但编码时发现不了
JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
ArrayList<Integer> collection1=new ArrayList<Integer>();
ArrayList<String> collection2=new ArrayList<String>();
System.out.println(collection1.getClass()==collection2.getClass());//结果为true所以当编译后所设置指向的类型被去掉了指向同一份字节码
泛形的基本术语,以ArrayList<E>为例:<>念着typeof
ArrayList<E>中的E称为类型参数变量
ArrayList<Integer>中的Integer称为实际类型参数
泛型的使用方法
使用泛形时的几个常见问题:
使用泛形时,泛形类型须为引用类型,不能是基本数据类型
如果两边都用泛型,则类型必须一致
如果只有一边使用泛型,另外一边不使用泛型,亦可.
Java程序中的普通方法、构造方法和静态方法中都可以使用泛型。方法使用泛形前,必须对泛形进行声明,语法:<T> ,T可以是任意字母,但通常必须要大写。<T>通常需放在方法的返回值声明之前。例如:
public<T,E> void test(T t,E e)
publicstatic <T> void doxx(T t);
类名后也可以声明泛型,这样在非静态函数中,就可以直接使用,而不需再次声明.
比如: public class Cat<T>
注意,类名后声明的泛型,在静态函数中是不能直接使用的,仍然需要自己声明,注意T的位置在static后.
publicstatic <T> void doxx(T t);
如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:
public class SQlDao<T> {
private T field1;
public void save(T obj){}
public T getId(int id){}
}
注意,静态方法不能使用类定义的泛形,而应单独定义泛形。
泛型的通配符?使用?通配符主要用于引用对象,使用了?通配符,就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。
泛型的高级应用——有限制的通配符
限定通配符的上边界:
1. 正确:Vector<? extends Number> x = new Vector<Integer>();
2. 错误:Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界:
1. 正确:Vector<? super Integer> x = new Vector<Number>();
2. 错误:Vector<? super Integer> x = new Vector<Byte>();
参数化类型不考虑类型参数的继承关系
错误的:Vector<Object> v=new Vercor<String>
1.线程就是程序运行中的一条路径,CPU调度和分派的基本单位
2..创建线程的两种方式:
a.定义一个类继承Thread类,重写run()方法,创建该类对象, 调用start()方法.
程序会开启一条新线程, 在新线程上自动调用run()方法.
b.定义一个类实现Runnable接口,实现run()方法,创建Thread对象,构造函数中传入Runnable对象,调用start()方法.这种方式的优势在于避免了单继承的局限性。
程序会开启一条新线程, 在新线程上自动调用Runnable的run()方法.
代码展示:
class Thread
{
public static void main(String[] args)
{
MyThread mt = new MyThread();
mt.start();
//****************************************
YourThread yt = new YourThread();
new Thread(yt).start();
}
}
class MyThread extends Thread
{
public void run()
{
//将需要运行的代码写在这里
}
}
class yourThread implements Runnable
{
public void run()
{
//将需要运行的代码写在这里
}
}
3.run与start的区别:开启run方法时,只有主函数一个线程在执行。
4.同步:A:代码中,线程的安全隐患是如何造成的:但多条语句对同一资源进行操作,而这些语句没多线程分开执行,就容易造成线程安全问题。因此,要保证在同一时刻,只有一个线程来执行这些操作资源的代码,可通过同步代码块完成,其实就是锁原理。B:同步的弊端在于降低了程序的效率,因为判断锁是对资源的一种消耗。C:同步的前提:必须是2个或2个以上线程;保证多个线程使用同一个锁。
D:同步的2种实现方式:同步代码块,同步函数(使用的锁是this)
补充:静态同步函数使用的锁是该方法所属类的字节码文件对象。因为static是随着类的加载而加载的,此时还没有建立该类的对象,只有类被加载进了内存,这时只有所属类的字节码文件对象。
5. 用同步优化个健全单例设计模式中的懒汉式。
A:直接用同步函数优化:解决安全问题,但效率超低。
class Single
{
private static Single s = null;
private Single(){}
public static synchronized Single getInstance()
{
if(s == null)
s = new Single();
return s;
}
}
B:双重判断加同步代码块解决安全问题,提高效率。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s == null)
s = new Single();
}
}
return s;
}
}
顺便复习一下饿汉式:
class Single
{
private static final Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
6.同步中的死锁现象:通常发生在同步嵌套的嵌套.
class Demo implements Runnable
{
private boolean flag;
Demo(boolean flag)
{
this.flag = flag ;
}
public void run()
{
if(flag)
{
synchronized(MyLock.lock1)
{
System.out.println(Thread.currentThread().getName()+"...if....lock1");
synchronized(MyLock.lock2)
{
System.out.println(Thread.currentThread().getName()+"... if...lock2");
}
}
}
else
{
synchronized(MyLock.lock2)
{
System.out.println(Thread.currentThread().getName()+"..else....lock2");
synchronized(MyLock.lock1)
{
System.out.println(Thread.currentThread().getName()+"..else...lock1");
}
}
}
}
}
class MyLock
{
static MyLock lock1 = new MyLock();
static MyLock lock2 = new MyLock();
}
class DeadLock
{
public static void main(String[] args)
{
Demo d1 = new Demo(true);
Demo d2 = new Demo(false);
Thread t1 = new Thread(d1);
Thread t2 = new Thread(d2);
t1.start();
t2.start();
}
}
7.同一资源被不同线程操作,而且这些线程动作不一致时,就叫做线程通讯.
8.wait(),notify,notifyAll()用来操作线程却定义在了object类中是因为:这些方法存在在同步中,使用它们必须标识所属的同步锁,而锁可以是任意对象,任意对象调用的方法一定定义在object类中。
9.wait():释放资源释放锁,sleep();释放资源不释放锁。
10.停止线程:停止线程的两种方式:
A.定义标记,让run方法结束。
run方法中一般都定义循环。只要控制住循环条件即可。
但是这种方式有局限性,如果线程进入到冻结状态,是不会读取标记的。那么线程是不会停止的。
B.中断线程。其实就是清除线程的冻结状态,让线程恢复到可运行状态,这样就可以让线程去读取标记,并结束线程。
停止线程原理:就是让run方法结束。
代码演示:
class StopThread implements Runnable
{
private boolean flag = true;
public synchronized void run()
{
while(flag)
{
try
{
wait();
}
catch (InterruptedException e)
{
System.out.println(Thread.currentThread().getName()+"...exception....");
flag = false;
}
System.out.println(Thread.currentThread().getName()+"....");
}
}
public void change()
{
flag = false;
}
}
class ThreadDemo13
{
public static void main(String[] args)
{
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while(true)
{
if(num++==50)
{
//st.change();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"...."+num);
}
}
}
---------------------- android培训、java培训、期待与您交流! ----------------------