三十五、内部类和匿名内部类
1.什么是内部类
class A{
class B{
}
}
编译后产生两个文件:A.class 和A$B.class
2.内部类的使用方法
class A{
int i;
class B{ //内部类可以随意使用外部类的成员变量和成员函数。
int j; //每一个内部对象都对应一个外部对象
int funB(){
int result = i + j; //A.this.i + j
return result;
}
}
}
class test{
public static void main(String[] args){
A a = new A();
//A.B b = new A().new B(); 生成内部对象的代码。
A.B b = a.new B();
a.i = 3;
b.j = 1;
int result = b.funB();
System.out.println(result);
}
}
3.匿名内部类的使用方法
一个接口A,一个类B,B中有一个函数fun调用A的对象作为参数时,调用fun的过程:
1)定义接口A
interface A{
public void dosomething();
}
2)定义B
class B{
public void fun(A a){
System.out.println("method fun of class B!");
a.dosomething();
}
}
3)定义A的实现类
class AImpl implements A{
public void dosomething(){
System.out.println("dosomething!");
}
}
4)生成AImpl的对象,向上转型成A的对象;生成B的对象;调用fun函数。
class Test{
public static void main(String[] args){
A a = new AImpl();
B b = new B();
b.fun(a);
//不使用匿名内部类,需要定义一个A的实现类AImpl,然后实例化AIpl,并向上转型为A的对象。
//使用匿名内部类,可以去掉定义A的实现类的步骤。直接生成一个没有名字的A实现类的对象作为fun函数的参数。
/*B b = new B();
*b.fun(new A(){ 匿名实现类直接在大括号里复写接口里的函数。
* public void dosomething(){
* System.out.println("anonymous inner classes");
* }
*});
*/
}
}
匿名内部类一般情况下都是写在参数里面的。
总结:
内部类就是一个类定义在另外一个类的内部,内部类可以随意使用外部类的成员变量和成员函数。生成内部类的对象的方法是:A.B b = new A().new B();
匿名内部类就是new一个接口,后面紧跟着一个类来实现这个接口,只不过这个类没有名字。
三十六、java当中的线程(一)
1.进程和线程
多进程:在操作系统中能(同时)运行多个任务(程序)。
多线程:在同一应用程序中有多个顺序流(同时)执行。线程是进程当中一个程序执行流程。
2.多线程程序运行模式
线程的生命周期:
线程是一个对象。
3.定义线程的方法
创建线程的方法一:
定义一个线程类,它继承Thread并重写其中的方法run()。方法run()称为线程体;由于java只支持单继承,用这种方法定义的类不能再继承其他类。
class FristThread extends Thread{
public void run(){
for(int i = 0; i < 100;i++){
System.out.println("FristThread ——>>"+i);
}
}
}
class Test{
public static void main(String[] args){
//生成一个线程类的对象
FristThread ft = new FristThread();
//启动线程
ft.start();
//ft.run(); 这不是启动线程的代码,不要这样写。它不会启动线程,而是直接在主线程里直接先执行完run里面的代码。
for(int j = 0;j< 120;j++){
System.out.println("main ——>>"+j);
}
}
}
运行结果:
多线程程序执行的特点就是:没谱!哪个线程什么时候执行,取决于哪个线程抢到了CPU。所有每次运行的结果都不一样。
总结:
所谓线程,就是进程中的进一步分支,如果一个应用程序中有多个线程的话,那么这些线程会来回切换着运行。
三十七、java中的线程(二)
1.实现线程的第二种方法(用得更多)。
创建线程的方法二:
提供一个实现接口Runnable的类做为线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体。
线程和线程体进行了分离。
class RunnableImpl implements Runnable{
public void run(){
for(int i = 0; i < 100; i++){
System.out.println("Runnable ——>"+i);
}
}
}
class Test{
public static void main(String[] args){
// 生成一个Runnable接口实现类的对象
RunnableImpl ri = new RunnableImpl();
//生成一个Thread对象,并将Runnable接口实现类的对象作为参数传递给该Thread对象。
Thread t = new Thread(ri);
//通知Thread对象,执行start方法
t.start();
}
}
方法一和方法二都对run这个方法进行了复写,区别在于,一个是直接继承Thread;一个是实现了Runnable这个接口,这样避免了该线程类不能继承其他类的情况。
在实际开发过程中,继承能不用就不用,因为java中只支持单继承。
2.控制线程的常见函数。
中断线程
—Tread.sleep() //后面要有一个参数,为毫秒数。线程体中执行了此段代码,当前线程就进入休眠状态,休眠时间到了之后,线程进入就绪状态。
—Tread.yield() //线程体重执行了此段代码,当前线程会让出CPU,但是仍保持就绪状态,跟其他线程抢CPU。
class RunnableImpl implements Runnable{
public void run(){
for(int i = 0; i < 100; i++){
System.out.println("Runnable ——>"+i);
try{
if(i == 50){
Thread.sleep(4000); //会产生中断,所以要用try。
}
}
catch(Exception e){
System.out.println(e);
}
}
}
}
设置线程的优先级
—getPriority()
—setPriority()
class Test{
public static void main(String[] args){
RunnableImpl ri = new RunnableImpl();
Thread t = new Thread(ri);
//线程的优先级最大是10,最小是1,可以使用Thread所提供的静态常量或者1-10的整数来设置线程的优先级,
//数字越大,线程执行的概率越高。
// t.setPriority(Thread.MAX_PRIORITY); //设置最大优先级
t.setPriority(Thread.MIN_PRIORITY); //设置最小优先级
System.out.println(t.getPriority()); //获取优先级,并打印出来
t.start();
}
}
三十八、java当中的线程(三)
1.多线程数据安全(本讲主要讲保证数据的完整性)
多线程共用一份资源时,要么给每个线程复制一份数据,要么使用同步代码块。
2.同步线程的方法
使用同步锁 synchronized(this){代码},保证多线程共用数据时的数据安全。
class MyThread implements Runnable{
int i = 100;
public void run(){
while(true){
synchronized(this){ //同步锁,没有拿到这个锁时,线程等待。
System.out.println(Thread.currentThread().getName()+i);
i--;
Thread.yield();
if(i < 0){
break;
}
}
}
}
}
class Test{
public static void main(String[] args){
MyThread mt = new MyThread();
//生成两个Thread对象,但是这两个Thread对象公用同一个线程体
Thread t1 =new Thread(mt);
Thread t2 =new Thread(mt);
//每一个线程都有名字,可以通过Thread对象的setName()方法设置线程名字,也可以使用getName()方法获取线程对象的名字;
t1.setName("thread1 ");
t2.setName("thread2 ");
//分别启动两个线程
t1.start();
t2.start();
}
}