美文网首页java基础入门
反射与线程间通讯

反射与线程间通讯

作者: 阿Q说代码 | 来源:发表于2019-03-11 17:08 被阅读0次

    反射

    一、在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。

    注:反射的步骤

    A:首先学习字节码文件

    B:第二学习获取字节码文件的构造方法,并创建对象

    C:有了对象了,就要学会获取对象中的成员变量## 多线程与同步代码块详解

    D:能获取对象中的成员变量了,那么还要学习成员方法

    二、1)字节码文件的三种获取方式

    ①Object类的getClass()方法:对象.getClass()

    Person p = new Person();
    Class c = p.getClass();
    

    注意所有同一个类的字节码文件对象(实例)都是同一个(因为一个类只有唯一的字节码文件)

    比如:

    Person p = new Person();
    Class c = p.getClass();
    
    Person p2 = new Person();
    Class c2 = p2.getClass();
    
    System.out.println(p == p2);// false
    System.out.println(c == c2);// true
    

    ②数据类型的静态的class属性:类名.class;例如:Class c3 = Person.class;

    ③通过Class类的静态方法forName(String className)(一般只用最后一种,前面两种了解即可)

    Class c4 = Class.forName("com.itcast.Person");//通过包路径获取类字节码文件

    2)反射获取类的构造方法

    • public Constructor<?>[] getConstructors():所有公共构造方法

    • public Constructor<?>[] getDeclaredConstructors():所有构造方法,包括私有

    • public Constructor<T> getConstructor(Class<?>... parameterTypes):获取单个构造方法

    比如:

    Class clazz = Class.forName("com.itcast.Person");
    Constructor c = clazz.getConstructor(String.class,int.class);//获取有参构造
    Person p = (Person) c.newInstance("张三",23);   //通过有参构造创建对象
    System.out.println(p);
    

    3)反射获取类的成员变量

    • Field[] fields = c.getFields();// 获取所有公共的成员变量
    • Field[] fields = c.getDeclaredFields();// 获取所有的成员变量
    • Field field = c.getField("age");// 获取单个的成员变量

    比如:

    Class clazz = Class.forName("com.itcast.Person");
    Constructor c = clazz.getConstructor(String.class,int.class);   //获取有参构造
    Person p = (Person) c.newInstance("张三",23);                     //通过有参构造创建对象    //修改姓名的值
    Field f = clazz.getDeclaredField("name");                       //暴力反射获取字段
    f.setAccessible(true);                                          //去除私有权限
    f.set(p, "李四"); 
    System.out.println(p);
    

    4)反射获取类的成员方法

    • Method[] methods = c.getMethods();// 所有公共方法,包括父类的
    • Method[] methods = c.getDeclaredMethods();// 本类的所有方法
    Class clazz = Class.forName("com.heima.bean.Person");
    Constructor c = clazz.getConstructor(String.class,int.class);   //获取有参构造
    Person p = (Person) c.newInstance("张三",23);                     //通过有参构造创建对象
    
    Method m = clazz.getMethod("eat");                              //获取eat方法
    m.invoke(p);
    
    Method m2 = clazz.getMethod("eat", int.class);                  //获取有参的eat方法
    m2.invoke(p, 10);
    

    三、案例:动态创建某个配置文件中提供的一个类的名字的这个类的对象,并执行其方法

    public class DemoClass {
        public void run() {
            System.out.println("welcome to heima!");
        }
    }
    //创建输入流关联xxx.properties
    BufferedReader br = new BufferedReader(new FileReader("file.properties"));  
    Class clazz = Class.forName(br.readLine()); //读取配置文件中类名,获取字节码对象
    
    DemoClass dc = (DemoClass) clazz.newInstance(); //通过字节码对象创建对象
    dc.run();//执行方法
    

    四、泛型只是在编译期间(或者是你在写代码期间)强制要求你的做的一些规范,等编译通过生成了字节码文件后,泛型就会被擦除,运行期间就没有泛型了。
    五、public void setProperty(Object obj, String propertyName, Object value){},此方法可将obj对象中名为propertyName的属性的值设置为value。

    public class Tool {
        //此方法可将obj对象中名为propertyName的属性的值设置为value。
        public void setProperty(Object obj, String propertyName, Object value) throws Exception {
            Class clazz = obj.getClass();                   //获取字节码对象
            Field f = clazz.getDeclaredField(propertyName); //暴力反射获取字段
            f.setAccessible(true);                          //去除权限
            f.set(obj, value);
        }
    }
    
    public static void main(String[] args) throws Exception {
        Student s = new Student("张三", 23);
        System.out.println(s);
    
        Tool t = new Tool();
        t.setProperty(s, "name", "李四");
        System.out.println(s);
    }
    

    线程间通讯

    多个线程并发执行时,在默认情况下CPU是随机切换线程的,如果我们希望他们有规律的执行, 就可以使用通信。两个线程就用wait() 和notify();多个线程就用wait() 和notifyAll()。

    注意事项:

    1,这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用。

    2,为什么wait方法和notify方法定义在Object这类中?因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在Object这个类中。

    3,sleep方法和wait方法的区别?

    sleep方法必须传入参数,参数就是时间,时间到了自动醒来;wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待。sleep方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁睡;wait方法在同步函数或者同步代码块中释放锁。

    线程组
    Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。默认情况下,所有的线程都属于主线程组。

    public final ThreadGroup getThreadGroup();//通过线程对象获取他所属于的组

    public final String getName();//通过线程组对象获取他组的名字

    我们也可以给线程设置分组

    1,ThreadGroup(String name) 创建线程组对象并给其赋值名字

    2,创建线程对象

    3,Thread(ThreadGroup group, Runnable target, String name)

    4,设置整组的优先级或者守护线程

    多线程程序实现方式

    这种方式的好处,可以通过线程方法来返回一个结果,而run方法不能返回结果

    public class MyCallable implements Callable<Integer> {
        private int number;
    
        public MyCallable(int number) {
            this.number = number;
        }
        @Override
        public Integer call() throws Exception {
            int sum = 0;
            for (int x = 1; x <= number; x++) {
                sum += x;
            }
            return sum;
        }   
    }
    
    // 创建线程池对象
    ExecutorService pool = Executors.newFixedThreadPool(2);
    
    // 可以执行Runnable对象或者Callable对象代表的线程
    Future<Integer> f1 = pool.submit(new MyCallable(100));
    Future<Integer> f2 = pool.submit(new MyCallable(200));
    
    // V get()
    Integer i1 = f1.get();
    Integer i2 = f2.get();
    
    System.out.println(i1);
    System.out.println(i2);
    
    // 结束
    pool.shutdown();
    

    线程的生命周期:新建,就绪,运行,阻塞,死亡

    好了今天就先说到这了,想了解更多学习知识,请关注微信公众号“阿Q说”,获取更多学习资料吧!你也可以后台留言说出你的疑惑,阿Q将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

    相关文章

      网友评论

        本文标题:反射与线程间通讯

        本文链接:https://www.haomeiwen.com/subject/yiibpqtx.html