欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java(二十一)

程序员文章站 2022-07-07 21:30:08
...

知识点一:作业回顾

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

方法一:将字符作为数组下标,对字符串进行遍历。

@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();
        }
    }
相关标签: java java