Java(二十一)

知识点一:作业回顾

题目一:给定一个字符串, 统计每个字符出现的次数

方法一:将字符作为数组下标,对字符串进行遍历。
@Test
    public void test2() {
        String string = "ajfalkjsdflkajsdflasjdf348729384723984汉不苛是要困右百百呆在中2342lalakjfds";
        int[] arr = new int[65536];
        for (int i = 0; i < string.length(); i++) {
            char ch = string.charAt(i);
            arr[ch]++;
        }
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > 0) {
                System.out.println((char)i + ":" + arr[i]);
            }
        }
    }
方法二:利用get获取值对象,把字符作为键对象传入到hashMap中
@Test
    public void test1() {
        String string = "ajfalkjsdflkajsdflasjdf348729384723984汉不苛是要困右百百呆在中2342lalakjfds";
        // 'a' : 5, 's' : 8
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < string.length(); i++) {
            char ch = string.charAt(i);
            Integer count = map.get(ch);
            if (count == null) {
                count = 0;
            }
            map.put(ch, ++count);
        }
        System.out.println(map);
    }

题目二:复制某目录下文件

一:复制文件的方法写出来
public void copyFile(File file1, File file2) {
        System.out.println("复制文件:" + file1 + " 到 " + file2);
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(file1);
            fos = new FileOutputStream(file2);
            byte[] buf = new byte[8192];
            int count;
            while ((count = fis.read(buf)) != -1) {
                fos.write(buf, 0, count);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
二:复制目录的方法写出来
public void copyDir(File file1, File file2) {
        file2.mkdirs(); // 先把目标目录创建出来.
        File[] files = file1.listFiles();
        if (files == null) {
            System.out.println(file1 + " 不允许访问!!");
            return;
        }
        for (int i = 0; i < files.length; i++) {
            File target = new File(file2.getAbsolutePath() + "\\" + files[i].getName());
            if (files[i].isFile()) {
                // 直接复制文件
                copyFile(files[i], target);
            } else {
                // 如果是目录, 直接让子目录递归到目标的子目录中
                copyDir(files[i], target);
            }
        }
    }
三:实现
//把C:/Program Files 复制为 D:/a/Program Files
    @Test
    public void test3() {
        File tmp = new File("D:/a");
        tmp.mkdir();

        File file1 = new File("C:/Program Files");
        File file2 = new File(tmp, file1.getName());
        copyDir(file1, file2);

    }

知识点二:线程通信

线程通信这里我们使用的还是Account这个例子

使用wait和notify方法

(1)java Bean


public class Account {

    private String name;
    private int balance;

    public Account() {}

    public Account(String name, int balance) {
        this.name = name;
        this.balance = balance;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "name='" + name + '\'' +
                ", balance=" + balance +
                '}';
    }
}

(2)存钱

public class Deposit implements Runnable {

    private Account account;

    public Deposit(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            synchronized ("") {
                int balance = account.getBalance();
                account.setBalance(balance + 1000);
                System.out.println(Thread.currentThread().getName() + " 存完钱 : " + account);
                "".notify();
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

(3)取钱

public Withdraw(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            synchronized ("") {
                if (account.getBalance() < 1000) {
                    System.out.println("钱不够, 进入等待");
                    try {
                        "".wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                account.setBalance(account.getBalance() - 1000);
                System.out.println(Thread.currentThread().getName() + " 取完钱后 : " + account);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

(4)实现

public class AccountTest {

    public static void main(String[] args) {
        Account a = new Account("张三", 0);

        Runnable runner2 = new Withdraw(a);
        Thread thread2 = new Thread(runner2);
        thread2.setName("取钱柜台1");
        thread2.start();

        Runnable runner1 = new Deposit(a);
        Thread thread1 = new Thread(runner1);
        thread1.setName("存钱柜台1");
        thread1.start();


    }
}

知识点三:wait和notify的用法

public class PrintRunner implements Runnable {

    private int i = 1;

    @Override
    public void run() {
        for (int j = 0; j < 50; j++) {
            synchronized ("") {
                "".notify();
                System.out.println(Thread.currentThread().getName() + " : " + i++);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (j < 49) {
                    try {
                        "".wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
public class PrintRunnerTest {

    public static void main(String[] args) {
        PrintRunner printRunner = new PrintRunner();
        Thread thread1 = new Thread(printRunner);
        Thread thread2 = new Thread(printRunner);

        thread1.setName("线程1");
        thread2.setName("线程2");

        thread1.start();
        thread2.start();
    }
}

知识点四:反射

一、理解

反射:用另一种创建对象,使用对象

反射的好处:把原来的编译错误延迟成运行时异常。

Class clazz = Class.forName(全限定类名);//包名.子包名.子子子包名

Class时Java程序中的数据类型的描述

class Teacher extends HashMap implements Comparable, Serializable, Runnable {

    public static String school;

    public static void staticTest() {
        System.out.println("staticTest()...");
    }

    private String name;
    private int age;
    private String gender;

    public Teacher() {}

    public Teacher(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }

    private int lesson(String content, String room, int hours) {
        System.out.println("老师在[" + room + "]教室上[" + content + "]课, 共上了[" + hours + "]小时");
        //throw new RuntimeException("无端端的异常");
        return 10;
    }

    @Override
    public int compareTo(Object o) {
        return 0;
    }

    @Override
    public void run() {

    }
}

测试及使用

①正常使用
@Test
    public void test1() {
        // 创建对象
        /*
        Teacher t1 = new Teacher(); // 硬编码, 在编译时强烈的依赖类.
        t1.name = "宋红康";
        t1.age = 30;
        t1.gender = "男";

        System.out.println(t1.name);
        System.out.println(t1.age);
        System.out.println(t1.gender);

        System.out.println(t1);
        */

        Teacher t2 = new Teacher("佳佳", 20, "女");
        System.out.println(t2);


    }
②反射使用:根据类模板直接创建实体对象
 @Test
    public void test2() {
        try {
            // 类模板对象. 软编码, 在编译时不是强烈的依赖类.
            Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");// 手工加载类模板
            Object object = clazz.newInstance(); // 根据类模板直接创建实体对象, 无参构造器
            System.out.println(object);
        } catch (ClassNotFoundException e) { // 在运行时没有找到类, 或类名错误.
            e.printStackTrace();
        } catch (IllegalAccessException e) { // 对于访问的成员没有访问权限时, 出这个问题
            e.printStackTrace();
        } catch (InstantiationException e) { // 实例化异常, 在创建对象时出问题.
            e.printStackTrace();
        }
    }
③使用反射对非私有化 的属性进行赋值
@Test
    public void test3() {
        try {
            Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
            Object object = clazz.newInstance();
            // object.name = "宋宋"
            // 1) 向类模板对象要属性定义对象
            // 属性定义 : 修饰符, 数据类型, 属性名.
            Field nameField = clazz.getField("name"); // 提供属性名称 获取相应的属性定义对象
            // 2) 给属性赋值, 必须再定位目标this对象.
            nameField.set(object, "宋宋"); // object.name = "宋宋";
            Object name = nameField.get(object);
            System.out.println(name); // System.out.println(object.name);

            // 修改age属性
            Field ageField = clazz.getField("age");
            ageField.set(object, 30); // object.age = 30
            System.out.println(ageField.get(object));

            Field genderField = clazz.getField("gender");
            genderField.set(object, "男");
            System.out.println(genderField.get(object));

            System.out.println(object);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
④使用反射对私有化的属性进行赋值
@Test
    public void test4() {
        try {
            Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
            Object object = clazz.newInstance();
            //Field nameField = clazz.getField("name"); // getField方法只能获取到本类中的公共属性,还包括从父类继承的公共属性
            Field nameField = clazz.getDeclaredField("name"); // 获取本类中声明的所有属性, 包括私有的.
            System.out.println(nameField);
            nameField.setAccessible(true); // 设置为可访问. 暴力反射.
            nameField.set(object, "宋宋");
            Object name = nameField.get(object);
            System.out.println(name);

            Field ageField = clazz.getDeclaredField("age");
            ageField.setAccessible(true); // 突破封装性
            ageField.set(object, 30);

            Field genderField = clazz.getDeclaredField("gender");
            genderField.setAccessible(true);
            genderField.set(object, "男");

            System.out.println(object);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) { // 对于访问的成员没有访问权限
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) { // 没有这个属性
            e.printStackTrace();
        }
    }
⑤获取类模板的途径有4种
@Test
    public void test5() throws Exception {
        // 获取类模板对象的途径 有4种
        // 1) 已知类, 通过类的静态属性.class来获取,最为安全可靠,程序性能最高
        Class clazz1 = Teacher.class; // 使用最多

        // 2) 已经拥有了对象, 然后通过对象进一步获取它对应的类模板
        Teacher teacher = new Teacher("佟刚", 40, "男");
        Class clazz2 = teacher.getClass();
        System.out.println(clazz1 == clazz2);

        // 3) 作为反射的第一条语句
        Class clazz3 = Class.forName("com.atguigu.javase.reflect.Teacher");
        //System.out.println(clazz3);
        System.out.println(clazz1 == clazz3);

        // 4) 先获取一个类加载器对象, 再通过类加载器对象的loadClass方法
        // 下面的代码是固定的写法,用于获取当前类的类载器
        //ClassLoader classLoader = this.getClass().getClassLoader();// 每个类模板一定知道是哪个类加载器加载的它
        ClassLoader classLoader = ReflectTest.class.getClassLoader();// 每个类模板一定知道是哪个类加载器加载的它
        Class clazz4 = classLoader.loadClass("com.atguigu.javase.reflect.Teacher");
        System.out.println(clazz3 == clazz4);

        Class<? extends Serializable> aClass = new Serializable() {}.getClass();

        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
        for (int i = 0; i < declaredConstructors.length; i++) {
            System.out.println(declaredConstructors[i]);
        }
        Constructor<? extends Serializable> declaredConstructor = aClass.getDeclaredConstructor(ReflectTest.class);
        declaredConstructor.setAccessible(true);
        Serializable serializable = declaredConstructor.newInstance(this);
        System.out.println(serializable);
    }

二、双亲委派机制

// 双亲委派机制
// 1) 首先由系统类加载器发起类加载请求.
// 2) 把加载任务委托给父类加载器:扩展类加载器
// 3) 扩展类加载器委托给引导类加载器, 此时引导类加载器要判断, 如果不是核心类, 驳回请求
// 4) 扩展类加载器进一步也要判断, 是我该由加载, 如果也不该我加载, 驳回请求
// 5) 系统类加载器发现全部被驳回后, 自己直接加载了.

// 1) 首先由系统类加载器发起类加载请求.
// 2) 把加载任务委托给父类加载器:扩展类加载器
// 3) 扩展类加载器委托给引导类加载器, 此时引导类加载器要判断, 是核心类, 当仁不让, 立刻加载
// 4) 扩展类加载器发现已经加载过了, 不加载并返回
// 5) 系统类加载器发现已经加载过了, 不加载并返回.
@Test
    public void test8() {
        // 系统类加载器是最常用, 主要用于加载我们自定义类
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        // 扩展类加载器, 负责加载jre/lib/ext目录下的所有jar
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);

        // 引导类加载器, 是最底层最核心的类加载器, 负责加载jre/lib目录下的所有.jar.
        ClassLoader boostrapClassLoader = extClassLoader.getParent();
        System.out.println(boostrapClassLoader);
}
①类的加载可以加载各种资源。只要是项目所包含的.jar文件或src目录下 的所有资源,它可以加载classpath路径中的任意文件
@Test
    public void test9() throws IOException {
        // 类加载可以 加载各种资源, 只要是项目所包含的.jar文件或src目录下的所有资源.
        // 它可以加载classpath路径中的任意文件
        //InputStream is = this.getClass().getClassLoader().getResourceAsStream("com/sun/corba/se/impl/logging/LogStrings.properties");
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("com/atguigu/javase/hello.properties");
        Properties properties = new Properties();
        properties.load(is);

        Iterator<Map.Entry<Object, Object>> iterator = properties.entrySet().iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        //"javax/sql/rowset/rowset.properties"
    }
②构造器的反射应用
@Test
    public void test10() {
        Class clazz = null;
        try {
            clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
            //Object object = clazz.newInstance();
            //public Teacher(String name, int age, String gender) {
            // 找到指定的构造器, 参数中提供构造方法的形参类型列表
            Constructor constructor = clazz.getConstructor(String.class, int.class, String.class);
            // newInstance()调用时必须传递和形参一致的实参列表
            Object object = constructor.newInstance("宋宋", 30, "男"); // 相当于new Teacher("宋宋", 30, "男");
            System.out.println(object);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

⑤方法的反射应用
@Test
    public void test11() {
        try {
            Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
            Object object = clazz.newInstance();
            //((Teacher)object).lesson("Mysql", "302", 2);
            // 必须提供方法名, 和方法的形参类型列表
            // getMethod()只能获取公共方法, 包括父类继承的.
            //Method m1 = clazz.getMethod("lesson", String.class, String.class, int.class);
            // getDeclaredMethod获取本类中声明的所有方法, 包括私有的.
            Method m1 = clazz.getDeclaredMethod("lesson", String.class, String.class, int.class);
            m1.setAccessible(true);
            // 必须再通过m1调用, 如果方法是void, 它的返回值就是null, 提供实参列表
            Object retValue = m1.invoke(object, "MySQL", "302", 3);//object.lesson("Mysql", "302", 2);
            System.out.println(retValue);

            Method hashCode = clazz.getMethod("hashCode");// 获取父类继承来的公共方法. 方法没有参数, 不需要提供参数列表
            System.out.println(hashCode.invoke(object)); // object.hashCode(), 方法没有参数, 也不需要提供实参列表.

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) { // 没有访问权限
            e.printStackTrace();
        } catch (InstantiationException e) { // 创建对象失败
            e.printStackTrace();
        } catch (NoSuchMethodException e) { // 没有找到方法.
            e.printStackTrace();
        } catch (InvocationTargetException e) { // 调用的目标方法出问题时.
            e.printStackTrace();
        }
    }
⑥静态属性的反射
 @Test
    public void test12() {
        try {
            Class clazz = Class.forName("com.atguigu.javase.reflect.Teacher");
            Field school = clazz.getField("school");
            school.set(null, "sgg"); // Teacher.school = "sgg";, 第一个参数会被完全忽略
            System.out.println(school.get(null)); // 静态属性的访问不需要对象, 所以参数中数据被忽略

            Class superclass = clazz.getSuperclass(); // 获取父类
            System.out.println(superclass);

            Class[] interfaces = clazz.getInterfaces();
            for (int i = 0; i < interfaces.length; i++) {
                System.out.println(interfaces[i]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值