JavaSE作业题

数组循环题

JDK,JRE,JVM三者关系,JDK,JRE的结构有哪些

JDK是Java开发工具包,JRE是Java运行环境,JVM是Java虚拟机
JDK = JRE + Java开发工具
JRE = JVM + Java核心类库

一维数组初始化的两种方式

int[] i = new int[]{…};
int[] i = new int[10];

二维数组初始化的三种方式

int[][] i = new int[10][10];
int[][] i = new int[10][];
int[][] i = new int[][]{{},{}…}

如何遍历二维数组

for(int i = 0;i < arr.length;i++){
for(int j = 0;j < arr[i].length;j++){
System.out.println(arr[i][j]);
}
}

----------------------------------------------
求100以内的质数
能整除1和本身的数就是质数

public class Test {
    public static void main(String[] args) {
        //求100以内的质数:能整除1和本身的数就是质数
        for (int i = 2; i < 101; i++) {
            //标记,重置
            boolean flag = true;
            for (int j = 2; j < i; j++) {
                if (i % j == 0){
                    flag = false;
                    break;
                }
            }
            //循环完成判断flag,如果是false表示不是质数,是true就是质数
            if (flag){
                System.out.println(i + "是质数!");
            }
        }
    }
}
结果:2是质数!3是质数!5是质数!7是质数!11是质数!13是质数!17是质数!19是质数!23是质数!29是质数!31是质数!37是质数!41是质数!43是质数!47是质数!53是质数!59是质数!61是质数!67是质数!71是质数!73是质数!79是质数!83是质数!89是质数!97是质数!

-----------------------------------------------
求1000以内的完数:一个数等于它的因子之和的数就是完数,比如:完数6,它有约数1、2、3、6,除去它本身6外,其余3个数相加,1+2+3=6

public class Test {
    public static void main(String[] args) {
        /*求1000以内的完数:一个数等于它的因子之和的数就是完数,
        比如:完数6,它有约数1、2、3、6,除去它本身6外,其余3个数相加,1+2+3=6*/
        for (int i = 6; i < 1001; i++) {
            //记录总数
            int count = 0;
            for (int j = 1; j < i; j++) {
                if (i % j == 0){
                    count += j;
                }
            }
            if (i == count){
                System.out.print(i + "是完数!");
            }
        }
    }
}
结果:6是完数!28是完数!496是完数!

------------------------------------------------
使用二维数组打印10行杨辉三角
提示:
第一行有1个元素,第N行有N个元素
每行第一个和最后个元素是1
第三行开始,非第一个元素和最后一个元素,即yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j]

public class Test {
    public static void main(String[] args) {
        //声明二维数组
        int[][] yangHui = new int[10][];

        //循环赋值
        for (int i = 0; i < yangHui.length; i++) {
            yangHui[i] = new int[i + 1];

            //元素首末赋值1
            yangHui[i][0] = 1;
            yangHui[i][i] = 1;

            //再次循环赋值
            if (i > 1) {
                for (int j = 1; j < yangHui[i].length - 1; j++) {
                    yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j];
                }
            }
        }

        //遍历二维数组
        for (int i = 0; i < yangHui.length; i++) {
            for (int j = 0; j < yangHui[i].length; j++) {
                System.out.print(yangHui[i][j] + "  ");
            }
            System.out.println();
        }
    }
}
结果:
1  
1  1  
1  2  1  
1  3  3  1  
1  4  6  4  1  
1  5  10  10  5  1  
1  6  15  20  15  6  1  
1  7  21  35  35  21  7  1  
1  8  28  56  70  56  28  8  1  
1  9  36  84  126  126  84  36  9  1  

------------------------------------------------------------
定义int类型数组,长度10,分别赋值随机整数
求所有元素的最大值,最小值,和,平均值,并输出打印
要求随机数都是两位数

public class Test {
    public static void main(String[] args) {
        //定义数组
        int[] arr = new int[10];

        //循环赋值
        for (int i = 0; i < arr.length; i++) {
            //Math.random()默认0.0-1.0,需求是10-99,左闭右开
            arr[i] = (int) (Math.random() * 90) + 10;
        }

        //给数组排序
        Arrays.sort(arr);
        //全部打印输出
        System.out.println(Arrays.toString(arr));

        int sum = 0;
        //遍历数组
        for (int i = 0; i < arr.length; i++) {
            //第一个元素就是最小值
            if (i == 0){
                System.out.println("最小值是:" + arr[i]);
            }else if (i == arr.length - 1){//最后个元素就是最大值
                System.out.println("最大值是:" + arr[i]);
            }
            //和
            sum += arr[i];
        }

        System.out.println("和为:" + sum);
        System.out.println("平均值为:" + sum/ arr.length);
    }
}

---------------------------------------------------
数组的复制

public class Test {
    public static void main(String[] args) {
        //定义数组
        int[] array = {2,3,5,7,11,13,17,19};

        //复制数组
        int[] arr = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            arr[i] = array[i];
        }
        System.out.println(Arrays.toString(arr));
    }
}

------------------------------------------------------------------
反转数组

public class Test {
    public static void main(String[] args) {
        //定义数组
        String[] array = {"Aa", "Bb", "Cc", "Dd", "Ee"};

        //反转数组
        for (int i = 0, j = array.length - 1; i < j; i++, j--) {
            String swap = array[i];
            array[i] = array[j];
            array[j] = swap;
        }
        //遍历数组
        System.out.println(Arrays.toString(array));
    }
}

-------------------------------------------------------
二分法查找:
前提:数组是有序的

public class Test {
    public static void main(String[] args) {
        //定义数组
        int[] array = {1, 2, 3, 5, 8, 9, 11, 55, 66};

        //找出元素9
        int result = 9;
        result = 12;
        //起始位
        int start = 0;
        //结束位
        int end = array.length - 1;

        boolean flag = true;
        while (start <= end) {
            //中间位
            int middle = (start + end) / 2;
            if (result == array[middle]) {
                System.out.println("恭喜找到了!");
                flag = false;
                break;
            } else if (result > array[middle]) {
                start = middle + 1;
            } else if (result < array[middle]) {
                end = middle - 1;
            }
        }
        if (flag){
            System.out.println("没有这个数!");
        }
    }
}

-------------------------------------------
冒泡排序:相邻数字比较,交换位置

public class Test {
    public static void main(String[] args) {
        //定义数组,长度7
        int[] array = {9, 1, 2, 8, 3, 7, 6};

        for (int i = 0; i < array.length - 1; i++) {//外层控制比较次数
            for (int j = 0; j < array.length - 1 - i; j++) {//内循环比较大小
                if (array[j] > array[j + 1]){
                    int swap = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = swap;
                }
            }
        }
        System.out.println(Arrays.toString(array));
    }
}

面向对象题

面向对象思想编程内容的三条主线分别是什么?
1.类的组成:属性,方法,构造器,代码块,内部类
2.三大特征:封装,继承,多态
3.其他关键字:this,super,static,final,abstract,interface,package,import

谈谈你对面向对象中的类和对象的理解,并指出两者关系?
类:是程序员根据现实的事务所虚拟抽象出来的模板
对象:是现实中实际存在的个体,把世界分成不同的单元,每个单元都是独立的个体,多个个体组成起来形成功能系统
类实例化对象,对象抽象成类

面向对象思想的体现?
1.创建类
2.实例化对象
3.通过对象调用类的属性和方法

什么是方法的重载?
同一类体中,方法名相同,参数列表不同

Java方法的参数传递机制的具体体现?
基本数据类型:传递的是数据值
引用数据类型:传递的是地址值

构造器的作用?
创建对象并给实例变量赋值

类的属性赋值方式有几种,先后顺序是怎样的?
5种,默认初始化,显示初始化/代码块赋值,构造器初始化,对象.属性赋值

this关键字可以调用哪些结构?
属性,方法,其他构造器

四种权限修饰符是什么,并说明权限范围?
private:同类
缺省:同包,同类
protected:同包,同类,子类
public:同包,同类,子类,其他包

什么是多态性?什么是虚拟方法的调用?
1.父类引用指向子类对象
2.运行时调用的是子类重写的方法

方法重写的具体规则?
权限修饰符子类 >= 父类,返回值类型子类 <= 父类,方法名相同,参数列表相同,抛出的异常范围子类 <= 父类

super调用构造器需要注意什么?
super只能出现在构造器的首行,不能和this共存

如何实现向下转型,需要注意什么问题,如何解决问题
使用强转符(),可能会发生类型转换异常,用instanceof判断之后在向下转型

==和equals的区别
:可以比较基本数据类型和引用数据类型,基本数据类型比较的是数据值,引用类型比较的是地址值
equals:用来比较引用数据类型,底层用的是
,重写前比较的是地址值,重写后比较的是具体内容

写出八大基本类型对应的包装类
byte,short,int,long,float,double,boolean,char
Byte,Short,Integer,Long,Float,Double,Boolean,Character

基本数据类型,包装类,String类型三者之间的转换
基本数据类型 和 包装类,自动转换
基本数据类型(包装类) ==> String类型:用String.valueOf()或者加空串拼接
String类型 ==> 基本数据类型(包装类):XXX.parseXX("…")

static修饰的属性,跟实例变量有什么区别,至少三点
1.属性会随着类的加载而加载
2.保存的位置在方法区的静态域中
3.可以通过类名直接调用
4.静态属性无法声明在方法内

final可以修饰哪些结构,分别表示什么意思
final修饰的类无法被继承
final修饰的变量变成常量,必须赋值,并且无法修改
final修饰的方法无法被重写
final可以声明在方法内

代码实现单例模式的饿汉式和懒汉式

abstract能修饰哪些结构,有什么特点
abstract修饰的类是抽象类,无法实例化对象,提供构造器给子类创建对象
abstract修饰的方法是抽象方法,只有方法声明没有方法体,用来给子类重写
不能修饰变量

抽象类和接口的区别
抽象类:abstract修饰,有构造器,无法实例化,可以有普通方法,成员变量,类只支持单继承
接口:interface修饰,无构造器,无法实例化,只能定义静态常量和抽象方法,接口之间支持多继承,JDK之后可以定义静态方法和默认方法,有方法体

如何创建静态内部类和非静态内部类对象
class A{class B{}}
静态内部类对象:A.B v = A.new B();
非静态内部类对象:A.B v = new A().new B();

---------------------------------------------------------
定义Student类,三个属性:number(int)是学号,state(int)是年级,score(int)是成绩
创建20个学生对象,学号为1-20,年级和成绩由随机数确定
提示:生成随机数:Math.Random();返回double
四舍五入取整:Math.round(double);返回long
1.打印出3年级(state = 3)的学生信息
2.使用冒泡排序按学生成绩排序,并遍历所有学生信息

public class Test {
    public static void main(String[] args) {
        //创建数组长度20
        Student[] students = new Student[20];
        //遍历数组赋值
        getStudents(students);

        //遍历数组
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i].toString());
        }

        System.out.println("===========================");

        //打印出3年级(state = 3)的学生信息
        getState(students, 3);

        System.out.println("===========================");

        //使用冒泡排序按学生成绩排序,并遍历所有学生信息
        getScore(students);
    }

    //使用冒泡排序按学生成绩排序,并遍历所有学生信息
    public static void getScore(Student[] students) {
        for (int i = 0; i < students.length - 1; i++) {//比较19次
            for (int j = 0; j < students.length - 1 - i; j++) {
                if (students[j].score > students[j + 1].score) {
                    //必须调用的是属性才能交换,调用getter方法无效!!!
                    int swap = students[j].score;
                    students[j].score = students[j + 1].score;
                    students[j + 1].score = swap;
                }
            }
        }
        //遍历数组
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i].toString());
        }
    }

    //打印出3年级(state = 3)的学生信息
    public static void getState(Student[] students, int state) {
        for (int i = 0; i < students.length; i++) {
            if (students[i].getState() == state) {
                System.out.println(students[i].toString());
            }
        }
    }

    //数组遍历赋值
    public static Student[] getStudents(Student[] students) {
        for (int i = 0; i < students.length; i++) {
            int state = (int) (Math.random() * 6) + 1;
            int score = (int) (Math.random() * 101);
            students[i] = new Student((i + 1), state, score);
        }
        return students;
    }
}

class Student {

    private int number;//学号
    private int state;//年级
    int score;//成绩

    public Student(int number, int state, int score) {
        this.number = number;
        this.state = state;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "number=" + number +
                ", state=" + state +
                ", score=" + score +
                '}';
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getState() {
        return state;
    }

    public void setScore(int score) {
        this.score = score;
    }
}

-----------------------------------------------------------
画出以下方法的内存结构图

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.method01();
    }
    public void method01(){
        int i = 5;
        Value v = new Value();
        v.i = 25;
        method02(v,i);
        System.out.println(v.i);
    }

    private void method02(Value v, int i) {
        i = 0;
        v.i = 20;
        Value val = new Value();
        v = val;
        System.out.println(v.i + " " + i);
    }
}
class Value{
    int i = 15;
}

----------------------------------------------------------
定义Cricle类,double类型是属性radius是圆的半径,findArea方法是圆的面积,定义PassObject类,定义方法printAreas,具体是public void printAreas(Cracle c,int time),在printAreas方法打印输出1到time之间的每个整数半径值,以及对应的面积,比如time = 5,则输出半径1,2,3,4,5以及对应的面积,最后在main方法调用printAreas方法,输出当前半径值和面积

public class Test {
    public static void main(String[] args) {
        //创建对象
        RassObject rassObject = new RassObject();
        //调用方法
        rassObject.printAreas(new Circle(),5);
    }
}

class Circle {
    double radius;//半径

    /**
     * 圆的半径
     */
    public double findArea() {
        return Math.PI * radius * radius;
    }
}

class RassObject {
    public void printAreas(Circle c, int time) {
        for (int i = 1; i <= time; i++) {
            c.radius = i;
            System.out.println("圆的半径为:" + i + "\t圆的面积为:" + c.findArea());
        }
    }
}
结果:
圆的半径为:1	圆的面积为:3.141592653589793
圆的半径为:2	圆的面积为:12.566370614359172
圆的半径为:3	圆的面积为:28.274333882308138
圆的半径为:4	圆的面积为:50.26548245743669
圆的半径为:5	圆的面积为:78.53981633974483

-----------------------------------------------------
定义类Account模拟账户,属性:id账号,balance余额,annualInterestRate年利率,方法:getter和setter,返回月利率方法getMonthlyInterest,取款方法withdraw,存款方法deposit,测试方法里创建账号为1122,余额为20000,年利率4.5%的Account对象,使用withdraw方法提款30000,并打印余额,再次提款2500,使用deposit方法存款3000,打印余额和月利率
提示:提款方法withdraw,需判断用户余额是否满足提款要求

创建类CheckAccount代表可透支账户继承账户类,定义属性overdraft代表可透支限额,重写withdraw方法,算法为:如果取款金额小于余额,直接取,如果取款金额大于余额,计算需要透支的额度,判断可透支额度overdraft是否足够支付本次透支需要,如果可以将余额修改为0,冲减可透金额,如果不可以,提示用户超过可透支的限额
测试类创建账号1122,余额20000,年利率4.5%,可透支5000
使用withdraw方法提款5000,打印余额和可透支金额
在使用withdraw提款18000,打印余额和可透支金额
在使用withdraw提款3000,打印余额和可透支金额

public class Test {
    public static void main(String[] args) {
        //创建账号
        Account account = new Account(1122, 20000, 0.045);
        //取款30000
        account.withdraw(30000);//余额不足,取款失败,当前余额为:20000.0
        //取款2500
        account.withdraw(2500);
        //存款3000
        account.deposit(3000);//存款3000.0成功,当前余额为:20500.0	月利率为:0.00375

        System.out.println("----------------------");
        //创建子类对象
        CheckAccount checkAccount = new CheckAccount(1122, 20000, 0.045, 5000);
        checkAccount.withdraw(5000);
        checkAccount.withdraw(18000);
        checkAccount.withdraw(3000);
    }
}

//账户类
class Account {
    private int id;//账号
    private double balance;//余额
    private double annualInterestRate;//年利率

    /**
     * 构造器
     *
     * @param id                 账号
     * @param balance            余额
     * @param annualInterestRate 年利率
     */
    public Account(int id, double balance, double annualInterestRate) {
        this.id = id;
        this.balance = balance;
        this.annualInterestRate = annualInterestRate;
    }

    /**
     * 获取月利率
     */
    public double getMonthlyInterest() {
        return annualInterestRate / 12;
    }

    /**
     * 取款
     */
    public void withdraw(double money) {
        //取款金额大于余额
        if (money > this.balance) {
            System.out.println("余额不足,取款失败,当前余额为:" + getBalance());
            return;
        }
        //更新余额
        setBalance(this.balance -= money);
    }

    /**
     * 存款
     */
    public void deposit(double money) {
        if (money > 0) {
            setBalance(this.balance += money);
            System.out.println("存款" + money + "成功,当前余额为:" + getBalance() +
                    "\t月利率为:" + getMonthlyInterest());
        }
    }


    //getter and setter
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getBalance() {
        return balance;
    }

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

    public double getAnnualInterestRate() {
        return annualInterestRate;
    }

    public void setAnnualInterestRate(double annualInterestRate) {
        this.annualInterestRate = annualInterestRate;
    }
}
/**
 * 可透支账户
 */
class CheckAccount extends Account {
    private double overdraft;//可透支限额

    public CheckAccount(int id, double balance, double annualInterestRate, double overdraft) {
        super(id, balance, annualInterestRate);
        this.overdraft = overdraft;
    }

    /**
     * 子类取款方法
     * @param money
     */
    @Override
    public void withdraw(double money) {
        //余额足够
        if (money <= getBalance() && money > 0) {
            setBalance(getBalance() - money);
            System.out.println("取款" + money + "成功,余额为:" + getBalance() + ",可透支金额为:" + overdraft);
            //需要透支消费
        } else if (money > getBalance() && money <= getBalance() + overdraft) {
            overdraft = this.overdraft - (money - getBalance());
            System.out.println("取款" + money + "成功," + "可透支金额剩余:" + overdraft);
            setBalance(0);
        } else {
            //透支了钱也不够
            System.out.println("超过可透支限额!");
        }
    }
}
结果:
余额不足,取款失败,当前余额为:20000.0
存款3000.0成功,当前余额为:20500.0	月利率为:0.00375
----------------------
取款5000.0成功,余额为:15000.0,可透支金额为:5000.0
取款18000.0成功,可透支金额剩余:2000.0
超过可透支限额!

---------------------------------------------------------------------
创建类Order,属性int orderId,String orderName,方法:getter和setter,构造器,重写父类equals方法,测试类创建两个对象,判断创建的两个对象内容是否相等

public class Test {
    public static void main(String[] args) {
        Order order1 = new Order(1, "1");
        Order order2 = new Order(1, "1");
        System.out.println(order1.equals(order2));
    }
}

class Order {
    private int orderId;
    private String orderName;

    public Order(int orderId, String orderName) {
        this.orderId = orderId;
        this.orderName = orderName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Order order = (Order) o;
        return orderId == order.orderId && Objects.equals(orderName, order.orderName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(orderId, orderName);
    }

    public int getOrderId() {
        return orderId;
    }

    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }
}
结果:true

------------------------------------------------------
利用Vector代替数组,从键盘读入学生成绩(以负数代表结束),找出最高分,并输出学生成绩等级
创建Vector对象,添加元素v.addElement(obj),获取元素v.elementAt(0),计算长度v.size()
若与最高分相差10分内A等,20分内B等,30分内C等,其他D等

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        Vector v = new Vector();

        int maxValue = 0;

        while (true) {
            System.out.println("从键盘读入学生成绩(以负数代表结束)");
            int score = scanner.nextInt();

            if (score < 0) {
                break;
            }

            if (score > 100) {
                System.out.println("输入的数据非法!");
                continue;
            }

            //添加成绩
            v.addElement(score);//自动装箱成对象
            //获取最大值
            if (maxValue < score) {
                maxValue = score;
            }
        }

        //等级
        char grade;
        //遍历,比较值
        for (int i = 0; i < v.size(); i++) {
            Object o = v.elementAt(i);
            //转换成int
            int score = (int) o;
            if (maxValue - score <= 10) {
                grade = 'A';
            } else if (maxValue - score <= 20) {
                grade = 'B';
            } else if (maxValue - score <= 30) {
                grade = 'C';
            } else {
                grade = 'D';
            }
            System.out.println("长度为:" + v.size() + "最大值为:" + maxValue);
            System.out.println("student-" + i + ": score is " + score + ",grade is " + grade);
        }
    }
}

---------------------------------------------------------
定义EcmDef类,接收命令行两个参数,要求不能输入负数,计算两数相除,对数据类型不一致抛出NumberFormatException,缺少命令行参数抛出ArrayIndexOutOfBoundsException,除0ArithmeticException,输入负数定义自定义异常EcDef进行异常处理,在主类EcmDef定义异常方法ecm完成两数相除功能,在main方法使用异常处理语句进行异常处理

public class Test {
    public static void main(String[] args) {
        try {
            //将字符串args解析成int
            int result1 = Integer.parseInt(args[0]);
            int result2 = Integer.parseInt(args[1]);
            System.out.println(EcmDef.ecm(result1, result2));
        } catch (NumberFormatException e) {
            System.out.println("数据类型不一致");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("缺少命令行参数");
        }catch (ArithmeticException e){
            System.out.println("除0");
        }catch (EcDef e){
            e.getMessage();
        }
    }
}

class EcmDef {
    public static int ecm(int i, int j) throws EcDef{
        if (i < 0 || j < 0){
            throw new EcDef("不能输入负数!");
        }
        return i / j;
    }
}
//自定义异常类
class EcDef extends Exception {
    static final long serialVersionUID = 1L;
    public EcDef(){

    }
    public EcDef(String message){
        super(message);
    }
}

多线程习题

谈谈你对程序,进程,线程的理解
程序:一段静态代码
进程:一个正在进行的应用程序
线程:进程的一个执行场景

什么场景下存在线程安全问题,怎么解决?
多线程环境下对共享的数据进行了修改操作
使用同步机制

画图说明线程的生命周期,以及切换状态使用的方法
新建:new线程对象
就绪:调用start方法,抢CPU时间片
运行:调用run方法执行
阻塞:sleep,wait方法,进入阻塞状态
消亡:run方法执行结束

谈谈同步代码块中涉及到的同步监视器和共享数据
同步监视器:俗称同步锁,锁的对象必须是多线程共享并且唯一
共享数据:多线程共同操作的数据
同步代码块:包含的是多线程共同操作数据的代码

sleep()和wait()的区别
sleep:是Thread的方法,不会释放对象锁,进入阻塞状态,线程进入一定时间休眠,休眠时间结束后,进入就绪状态抢CPU时间片,获取执行权进入运行状态直至消亡
wait:是Object的方法,释放对象锁后进入阻塞状态,让线程进入无期限等待,直到notify唤醒

创建多线程有几种方式
1.继承Thread
2.实现Runnable
3.实现Callable
4.线程池

------------------------------------------------------
创建两个分支线程,一个遍历100以内的偶数,一个遍历100以内的奇数

public class Test {
    public static void main(String[] args) {
        //创建两个分支线程,一个遍历100以内的偶数,一个遍历100以内的奇数
        Thread thread = new Thread(new MyThread());
        Thread thread2 = new Thread(new MyThread2());
        thread.setName("t1线程:");
        thread2.setName("t2线程:");
        thread.start();
        thread2.start();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            if (i % 2 == 0){
                //偶数
                System.out.println(Thread.currentThread().getName() + "输出偶数==>" + i);
            }
        }
    }
}
class MyThread2 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            if (i % 2 != 0){
                //奇数
                System.out.println(Thread.currentThread().getName() + "输出奇数==>" + i);
            }
        }
    }
}

--------------------------------------------------------------
两个顾客分别向同一账户存3000,每次存1000,存三次,每次存完打印账户余额

public class Test {
    public static void main(String[] args) {
        //两个顾客分别向同一账户存3000,每次存1000,存三次,每次存完打印账户余额
        //创建账户
        Account account = new Account(0.0);
        //创建顾客,共享同一账户
        Thread thread1 = new Thread(new Customer(account));
        Thread thread2 = new Thread(new Customer(account));
        thread1.setName("t1线程:");
        thread2.setName("t2线程:");
        thread1.start();
        thread2.start();
    }
}

//账户类
class Account {
    private double balance;//余额

    /**
     * 存钱
     * @param
     */
    public synchronized void addMoney(int money){
        if (money > 0){
            setBalance(getBalance() + money);
            System.out.println(Thread.currentThread().getName() + "存入" + money + "成功,余额为:" + getBalance());
        }
    }

    public Account(double balance) {
        this.balance = balance;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }
}
//顾客类
class Customer implements Runnable{
    private Account account;//账户

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

    @Override
    public void run() {
        //存三次
        for (int i = 0; i < 3; i++) {
            account.addMoney(1000);
        }
    }
}
结果:
t1线程:存入1000成功,余额为:1000.0
t1线程:存入1000成功,余额为:2000.0
t1线程:存入1000成功,余额为:3000.0
t2线程:存入1000成功,余额为:4000.0
t2线程:存入1000成功,余额为:5000.0
t2线程:存入1000成功,余额为:6000.0

---------------------------------------------------------------
生产者Producer将产品交给商店Clerk,消费者Customer从商店处取走商品,店员一次只能持有固定产品数比如20,如果生产者想继续生产,商店会叫停,如果有空位了再叫生产者生产,如果商店没有产品了,商店会叫消费者等待,如果商店有商品了再叫消费者取走商品

public class Test {
    public static void main(String[] args) {

        //创建店员对象
        Clerk clerk = new Clerk();
        Producer p1 = new Producer(clerk);
        Customer p2 = new Customer(clerk);
        p1.setName("生产者1号:");
        p2.setName("消费者2号:");
        p1.start();
        p2.start();
    }
}

//生产者
class Producer extends Thread {
    private Clerk clerk;//关联商店

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始生产......");
        while (true) {
            clerk.product();//生产之后给商店
        }
    }
}

//商店
class Clerk {
    private int number = 0;//商品的数量


    //进货产品
    public synchronized void product() {//锁是this,当前对象Clerk,Clerk只创建一个满足唯一
        if (number < 20) {
            //进货
            number++;
            System.out.println(Thread.currentThread().getName() + "开始进货第" + number + "个商品!");
            //消费不满足20个就可以继续生产
            notify();
        } else {
            //有20个商品了,停止进货
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //出售产品
    public synchronized void consume() {
        if (number > 0) {
            //出售
            System.out.println(Thread.currentThread().getName() + "开始消费第" + number + "个商品!!!");
            number--;
            //唤醒
            notify();
        } else {
            //等待有货
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//消费者
class Customer extends Thread {
    private Clerk clerk;//关联商店

    public Customer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "开始消费......");
        while (true) {
            clerk.consume();
        }
    }
}
结果:死循环

常用类习题

String,StringBuffer,StringBuilder三者区别
String:一旦创建不可改变,不适合做大量字符串拼接,存储在方法区的字符串常量池中,JDK9之后底层是byte数组,相较于char数组,内存更小
StringBuffer:是可变序列,线程安全,效率高于String,低于StringBuilder,适用于做大量字符串拼接操作
StringBuilder:是可变序列,非线程安全,效率最高,适用于做大量字符串拼接操作

什么是枚举类,枚举对象的声明修饰符有哪些
1.枚举类型对象是可数的,确定的
2.只能是public static final修饰

什么是元注解,Retention和target的作用
1.对注解进行解释说明的注解就是元注解
2.Retention:描述注解的生命周期,SOURCE:Java源文件,CLASS字节码文件,RUNTIME字节码文件并且能被反射
3.target:描述注解出现的位置,类上,属性上,方法上…

throw和throws的区别
throw:手动创建异常对象并抛出,出现在方法体内
throws:处理异常的方式之一,声明抛出,出现在方法声明最后

-----------------------------------------------------------------
将字符串"2020-09-08"转换为java.sql.Date

public class Test {
    public static void main(String[] args) {
        //将字符串"2020-09-08"转换为java.sql.Date
        String str = "2020-09-08";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date parseDate = sdf.parse(str);
            java.sql.Date sqlDate = new java.sql.Date(parseDate.getTime());
            System.out.println("sqlDate = " + sqlDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

集合练习题

集合Collection中存储的如果是自定义的类,需要自定义重写哪个方法,为什么?
equals方法,因为contains,remove方法底层比较的是对象的内容

ArrayList,LinkedList,Vector三者的区别
三者都是List接口的实现类,是有序可重复的
ArrayList:底层是数组结构,非线程安全,查询效率高,通过数组首元素下标计算其他元素下标偏移量快速定位,增删效率低,首尾元素不受影响,如果增加或者删除数组中某个元素,元素后面的其他元素下标全会受牵连,
调用add方法底层才会创建长度为10的数组,扩容为原数组的1.5倍
LinkedList:底层是双向链表,非线程安全,查询效率低,通过首节点元素的下标依次遍历数组中的元素,直到找到该元素,增删效率高,如果增加或者删除链表中的某个元素,其他元素不受影响
Vector:底层是数组结构,线程安全,效率低,底层创建长度为10的数组,扩容为原数组的2倍

List接口的常用方法,增删改查,插,长度,遍历
add添加/插入,remove删除,set修改,get查询,size长度,iterator遍历器

set存储数据的特点是什么,常见的实现类有哪些
set存储元素特点:单列集合,是无序不可重复的
实现类:HashSet,LinkedHashSet,TreeSet

Map集合存储数据的特点是什么,并指明key,value,entry存储数据的特点
双列集合,以键值对方式存储元素
key:无序不可重复
value:无序可重复
entry:无序不可重复

描述HashMap的底层原理
HashMap底层是哈希表,数组 + 链表 + 红黑树结构,添加元素时,类调用HashCode方法计算哈希值定位下标,如果下标处没有元素,则直接存储元素,有元素,则调用equals方法,返回false,则直接存储元素,返回true,则存储失败
调用put方法才会创建数组长度为16的数组,加载因子为0.75f,当链表元素个数 > 8,数组长度 > 64,则转换成红黑树结构

Map常用类有哪些,有什么特点
HashMap,HashTable,TreeMap
HashMap:非线程安全的,效率高,可以存储null的key和value,子类LinkedHashMap,可以按照添加元素的顺序遍历集合
HashTable:线程安全的,效率低,不能存储null的key和value,子类Properties,常用于配置文件,只能存储String类型
TreeMap:底层是红黑树,比较器Comparator默认从小到大排列

Collection和Collections的区别
Collection:是单列集合,子接口有List,Set
Collections:是操控Collection和Map的工具类

如何遍历Map的key集,value集,key-value集,使用上泛型

提供方法用于遍历HashMap<String,String>中所有的key,存入List返回,使用上泛型

Map常用方法有哪些
put,remove,put改,get,size,遍历

------------------------------------------------------------------
分析以下set集合能否存储成功

public class Test {
    public static void main(String[] args) {
        HashSet set = new HashSet();
        Person p1 = new Person(1, "AA");
        Person p2 = new Person(2, "BB");
        set.add(p1);
        set.add(p2);
        System.out.println(set);
        p1.name = "CC";
        set.remove(p1);//没有1,"CC"对应的HashCode值
        System.out.println(set);
        set.add(new Person(1, "AA"));//该位置的AA已被修改,所以AA可以存储
        System.out.println(set);
        set.add(new Person(1,"CC"));//集合里还没有CC的HashCode值,所以能存储
        System.out.println(set);

    }
}
class Person{
    int id;
    String name;

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

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}
结果:
[Person{id=1, name='AA'}, Person{id=2, name='BB'}]
[Person{id=1, name='CC'}, Person{id=2, name='BB'}]
[Person{id=1, name='CC'}, Person{id=1, name='AA'}, Person{id=2, name='BB'}]
[Person{id=1, name='CC'}, Person{id=1, name='AA'}, Person{id=1, name='CC'}, Person{id=2, name='BB'}]

IO流练习题

流的三种分类方式
流向:输入流,输出流
数据单位:字节流,字符流
流的角色:节点流,处理流

写出4个IO流中的抽象类,4个文件流,4个缓冲流
InputStream,OutInputStream,Reader,Writer
FileInputStream,FileOutInputStream,FileReader,FileWriter
BufferedInputStream,BufferedOutInputStream,BufferedReader,BufferedWriter

字节流和字符流的使用场景
字节流:处理非文本文件
字符流:处理文本文件

什么是URL,举个例子
URL:是统一资源定位符
new URL(“http://localhost:8080/projectName/userLogin?username=Tom&passworld=123”)

谈谈你对对象序列化机制的理解
序列化过程:内存数据传输到磁盘的过程就是序列化
反序列化:磁盘中的数据传输到内存中就是反序列化

对象实例化需要满足的条件
1.实现Serializable接口
2.提供序列化版本号
3.要求对象属性也是可序列化的

使用缓冲流实现a.jpg文件复制为b.jpg文件的操作

转换流是哪两类,作用是什么
InputStreamReader:将字节输入流转换成字符输入流,解码过程
OutputStreamWriter:将字节输出流转换成字符输出流,编码过程

创建一个与a.txt文件同目录下的另一个文件b.txt

复制某目录下的所有资源到另一目录

网络编程题

IP对应的类是什么,实例化类的方式是什么,两个常用方法是什么
InetAddress
InetAddress.getByName(String host);,InetAddress.getLocalHost();获取本地ip
getHostName(),getHostAddress()

传输层的TCP协议和UDP协议主要区别
TCP:可靠的数据传输(三次握手),进行大数据量的传输,效率高
UDP:不可靠,以数据报形式发送,限为64K,效率低

反射练习题

写出获取Class实例的三种方式
1.Class.forName(“全路径”)
2.类名.class
3.引用.getClass()

谈谈你对Class类的理解
Class实例对应这加载到内存中的一个运行时类

创建Class对应运行时类的对象的通用方法,代码实现,构造器方面需要满足什么要求
newInstance方法,创建了对应的运行时类的对象
必须有无参构造器,权限修饰符的权限要够

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值