关键字:static




类变量

静态变量的内存解析:
 
 

相关代码:
public class ChineseTest {
    public static void main(String[] args) {
        System.out.println(Chinese.nation); //null 没赋值前
        System.out.println(Chinese.nation); //中国 静态变量赋值之后
        Chinese c1 = new Chinese();
        c1.name = "姚明";
        c1.age = 40;
        c1.nation = "China";
        Chinese c2 = new Chinese();
        c2.name = "刘翔";
        c2.age = 39;
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c1.nation); // China
        System.out.println(c2.nation); // China
        c2.nation = "CHN";
        System.out.println(c1.nation); // CHN
        System.out.println(c2.nation); // CHN
    }
}
class Chinese { //中国人类
    //非静态变量、实例变量
    String name;
    int age;
    //静态变量、类变量
    /**
     * China
     * China
     * CHN
     * CHN
     */
    static String nation = "中国";
    /**
     * China
     * null
     * China
     * CHN
     */
//    String nation;
    @Override
    public String toString() {
        return "Chinese{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}类方法(class method)


案例1:
编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额"、“利率"、“最小余额", 定义封装这些属性的方法,账号要自动生成。 编写主类,使用银行账户类,输入、输出3个储户的上述信息。 考虑:哪些属性可以设计成static属性x
相关代码:
AccountTest 
public class AccountTest {
    public static void main(String[] args) {
        Account acct1 = new Account();
        System.out.println(acct1);
        Account acct2 = new Account("123456", 2000);
        System.out.println(acct2);
        Account.setInterestRate(0.0123);
        Account.setMinBalance(10);
        System.out.println("银行存款的利率为:" + Account.getInterestRate());
        System.out.println("银行存款的额度为:" + Account.getMinBalance());
    }
}
Account 
public class Account {
    private int id; //账号
    private String password; //密码
    private double balance; //余额
    private static double interestRate; //利率
    private static double minBalance = 1.0; //最小余额
    private static int init = 1001; //用于自动生成id的基数
    public Account(){
        this.id = init;
        init++;
        password = "000000";
    }
    public Account(String password, double balance) {
        this.password = password;
        this.balance = balance;
        this.id = init;
        init++;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
    public static double getInterestRate() {
        return interestRate;
    }
    public static void setInterestRate(double interestRate) {
        Account.interestRate = interestRate;
    }
    public static double getMinBalance() {
        return minBalance;
    }
    public static void setMinBalance(double minBalance) {
        Account.minBalance = minBalance;
    }
    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", password='" + password + '\'' +
                ", balance=" + balance +
                '}';
    }
}
面试题:
public class StaticTest {
    public static void main(String[] args) {
        Order order = null;
        //可以打印出来,静态并不依赖于对象,直接通过类调用即可
        order.hello(); //hello!
        System.out.println(order.count); //1
    }
}
class Order{
    public static int count = 1;
    public static void hello() {
        System.out.println("hello!");
    }
}本章总结:
 
 static关键字的使用
1. static:静态的
2.static 用来修饰的结构:属性、方法;代码块、内部类
3.static修饰属性
    3.1 复习:变量的分类
    方式1:按照数据类型:基本数据类型、引用数据类型
    方式2:按照类中声明的位置
        成员变量:按照是否使用static修饰进行分类:
            使用static修饰的成员变量:静态变量、类变量
            不使用static修饰的成员变量:非静态变量、实例变量
        局部变量:方法内、方法形参、构造器内、构造器形参、代码块内等。
    3.2 静态变量:类中的属性使用static进行修饰。
        对比静态变量与实例变量:
        ① 个数
            > 静态变量: 内存空间中只有一份,被类的多个对象所共享。
            > 实例变量: 类的每一个实例(或对象)都保存着一份实例变量。
        ② 内存位置
            > 静态变量: jdk6及之前:存放在方法区。jdk7之后:存放在堆空间
            > 实例变量: 存放在堆空间的对象实体中
        ③ 加载时机
            > 静态变量: 随着类的加载而加载,由于类只会加载一次,所以静态变量也只有一份。
            > 实例变量: 随着对象的创建而加载。每个对象拥有一份实例变量。
        ④ 调用者
            > 静态变量: 可以被类直接调用,也可以使用对象调用。
            > 实例变量: 只能使用对象进行调用。
        ⑤ 判断是否可以调用 ---> 从生命周期的角度解释
                        类变量             实例变量
           类             yes                no
           对象           yes                yes
        ⑥ 消亡时机
            > 静态变量: 随着类的卸载而消亡
            > 实例变量: 随着对象的消亡而消亡
4.static修饰方法:(类方法、静态方法)
> 随着类的加载而加载
> 可以通过"类.静态方法"的方式,直接调用静态方法
> 静态方法内可以调用静态的属性或静态的方法(属性和方法的前缀使用的是当前类,可以省略)
        不可以调用非静态的结构。(比如:属性、方法)
                      类变量             实例变量
        类             yes                no
        对象           yes                yes
> static修饰的方法内,不能使用this和super
> 补充:在类的非静态方法中,可以调用当前类中的静态结构(属性、方法)或非静态结构(属性、方法)
5.开发中,什么时候需要将属性声明为静态的?
    > 判断当前类的多个实例是否能共享此成员变量,且此成员变量的值是相同的。
    > 开发中,常将一些常量声明是静态的。比如:Math类中的PI
    什么时候需要将方法声明为静态的?
    > 方法内操作的变量如果都是静态变量(而非实例变量)的话,则此方法建议声明为静态方法
    > 开发中,常常将工具类中的方法,声明为静态方法。比如:Arrays类、Math类
 
 
单例 (Singleton)设计模式

单例模式和实现思路(如果我们要让类在一个虚拟机...):

单例(Singleton)设计模式-饿汉式

单例(Singleton)设计模式-懒汉式

单例模式的优点


总结:
1.设计模式概述: 设计模式是在大量的`实践中总结`和`理论化`之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索. 就像是经典的棋谱,不同的棋局,我们用不同的棋谱。"套路" 经典的设计模式一共有23种。 2.何为单例模式(Singleton): 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 3.如何实现单例模式(掌握): > 饿汉式 > 懒汉式 4.对比两种模式(特点、优缺点) 特点: > 饿汉式:“立即加载”,随着类的加载,当前的唯一实例就创建了 > 懒汉式:"延迟加载",在需要使用的时候,进行创建。 优缺点: > 饿汉式:(优点)写法简单,由于内存中较早加载,使用更方便、更快。是线程安全的。(缺点)内存中占用时间较长。 > 懒汉式: (缺点)线程不安全 (放到多线程章节时解决)(优点)在需要的时候进行创建,节省内存空间。
实例代码:
//饿汉式
public class BankTest {
    public static void main(String[] args) {
//        Bank bank1 = new Bank();
//        Bank bank2 = new Bank();
        Bank bank1 = Bank.getInstance();
        Bank bank2 = Bank.getInstance();
        System.out.println(bank1 == bank2); //true
    }
}
//饿汉式
class Bank {
    //1.类的构造器石私有化
    private Bank(){
    }
    //2.在类的内部创建当前类的实例
    //4.此属性也必须声明为static的
    private static Bank instance = new Bank();
    //3.使用getXXX()方法获取当前类的实例,必须声明为static的
    public static Bank getInstance(){
        return instance;
    }
}
//懒汉式
public class GirlFriendTest {
    public static void main(String[] args) {
        GirlFriend test1 = GirlFriend.getInstance();
        GirlFriend test2 = GirlFriend.getInstance();
        System.out.println(test1 == test2); //true
    }
}
class GirlFriend {
    //1.类的构造器私有化
    private GirlFriend() {
    }
    //2.声明当前类的实例化
    //4.此属性也必须声明为static的
    private static GirlFriend instance = null;
    //3.通过getXXX()获取当前类的实例,如果未创建对象,则在方法内部进行创建
    public static GirlFriend getInstance(){
        if(instance == null){
            instance = new GirlFriend();
        }
        return instance;
    }
}理解main方法的语法

方式2:使用main()的形参进行传值。 代码:
public class MainDemo {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            System.out.println("hello:" + args[i]);
        }
    }
}命令行的方式传值:在执行命令后空格 写上实参
idea的传值方式
点击编辑配置:


执行结果:

总结:
 
 main()方法的剖析
public static void main(string args[]){}
1.理解1: 看做是一个普通的静态方法
  理解2: 看做是程序的入口,格式是固定的。
2.与控制台交互
如何从键盘获取数据?
> 方式1:使用Scanner
> 方式2:使用main()的形参进行传值。
  命令行的方式传值  idea的传值方式 
 
相关代码:
MainTest 
public class MainTest {
    public static void main(String[] args) { //程序的入口
        String[] arr = new String[]{"AA", "BB", "CC"};
        Main.main(arr);
    }
}
class Main{
    public static void main(String[] args) { //看做是普通的静态方法
        System.out.println("Main的main()的调用");
        for(int i = 0; i < args.length; i++){
            System.out.println(args[i]);
        }
        /**
         * Main的main()的调用
         * AA
         * BB
         * CC
         */
    }
}
类的成员之四:代码块



总结:
 
 类的成员之四:代码块
回顾:类中可以声明的结构:属性、方法、构造器;代码块(或初始化块)、内部类
1.代码块(或初始化块)的作用:
(即初始化类或对象的成员变量)用来初始化类或对象的信息
2.代码块的修饰:
    只能使用static进行修饰。
3.代码块的分类:
    静态代码块:使用static修饰
    非静态代码块:没有使用static修饰
4.具体使用:
4.1 静态代码块:
    > 随着类的加载而执行
    > 由于类的加载只会执行一次,进而静态代码块的执行,也只会执行一次
    > 作用:用来初始化类的信息
    > 内部可以声明变量、调用属性或方法、编写输出语句等操作。
    > 静态代码块的执行要先于非静态代码块的执行
    > 如果声明有多个静态代码块,则按照声明的先后顺序执行
    > 静态代码块内部只能调用静态的结构(即静态的属性、方法),不能调用非静态的结构(即非静态的属性、方法)
4.2 非静态代码块:
    > 随着对象的创建而执行
    > 每创建当前类的一个实例,就会执行一次非静态代码块
    > 作用:用来初始化对象的信息
    > 内部可以声明变量、调用属性或方法、编写输出语句等操作。
    > 如果声明有多个非静态代码块,则按照声明的先后顺序执行
    >非静态代码块内部可以调用静态的结构(即静态的属性、方法),也可以调用非静态的结构(即非静态的属性、方法) 
 
代码:
 
 (1)声明User类
- 包含属性:userName(String类型),password(String类型),registrationTime(long类型),私有化
- 包含get/set方法,其中registrationTime没有set方法
- 包含无参构造,
    - 输出“新用户注册”,
    - registrationTime赋值为当前系统时间
    - userName就默认为当前系统时间值,
    - password默认为"123456"
- 包含有参构造(String userName,String password)
    - 输出“新用户注册”,
    - registrationTime赋值为当前系统时间,
    - username和password由参数赋值
- 包含public String getInfo()方法,返回:"用户名:xx,密码:xx,注册时间:xx"
(2)编写测试类,测试类main方法的代码
 
 
UserTest 
public class UserTest {
    public static void main(String[] args) {
        User u1 = new User();
        System.out.println(u1.getInfo());
        User u2 = new User("Tom","654321");
        System.out.println(u2.getInfo());
        System.out.println();
        User1 u3 = new User1();
        System.out.println(u3.getInfo());
    }
}
User1 
public class User1 {
    private String userName;
    private String password;
    private long registrationTime; //注册时间
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public long getRegistrationTime() {
        return registrationTime;
    }
    {
        System.out.println("新用户注册");
        registrationTime = System.currentTimeMillis(); //获取系统当前时间(距离1970-1-1 00:00:00的毫秒数)
    }
    //代码块的使用
    public User1(){
//        System.out.println("新用户注册");
//        registrationTime = System.currentTimeMillis(); //获取系统当前时间(距离1970-1-1 00:00:00的毫秒数)
        userName = System.currentTimeMillis() + "";
        password = "123456";
    }
    public User1(String userName, String password) {
//        System.out.println("新用户注册");
//        registrationTime = System.currentTimeMillis(); //获取系统当前时间(距离1970-1-1 00:00:00的毫秒数)
        this.userName = userName;
        this.password = password;
    }
    public String getInfo(){
        return "用户名:" + userName + ",密码:" + password + ",注册时间为:" + registrationTime;
    }
}Field,属性赋值过程
总结:
可以给类的非静态的属性(即实例变量)赋值的位置有: ① 默认初始化 ② 显式初始化 或 ⑤ 代码块中初始化 ③ 构造器中初始化 ****************************** ④ 有了对象以后,通过"对象.属性"或"对象.方法"的方法进行赋值 2.执行的先后顺序: ① - ②/⑤ - ③ - ④ 3.(超纲)关于字节码文件中的<init>的简单说明:(通过插件jclasslib bytecode viewer查看) > <init>方法在字节码文件中可以看到。每个<init>方法都对应着一个类的构造器。(类中声明了几个构造器就会有几个<init>) > 编写的代码中的构造器在编译以后就会以<init>方法的方式呈现 > <init>方法内部的代码包含了实例变量的显示赋值、代码块中的赋值和构造器中的代码。 > <init>方法用来初始化当前创建的对象的信息的。 4.给实例变量赋值的位置很多,开发中如何选? > 显示赋值:比较适合于每个对象的属性值相同的场景 > 构造器中赋值:比较适合于每个对象的属性值不相同的场景
相关代码:
public class FieldTest {
    public static void main(String[] args) {
        Order o1 = new Order();
        System.out.println(o1.orderId); //1 ---> 2 ---> 3
    }
}
class Order {
    /**
     * 显式初始化 与 代码块中初始化 可以更换位置
     * 此时的执行结果是1
     * 反之执行结果是2
     * order类的加载有一个系的过程,在初始化之前orderId就已经被默认初始化了,并且默认为0,在后面才开始显示赋值或者代码块赋值
     */
//    {
//        orderId = 2;
//    }
//    int orderId = 1;
    int orderId = 1;
    {
        orderId = 2;
    }
    //构造器会以init的方式呈现的字节码中
    //字节码暴露了我们加载的顺序
    public Order(){
        super();
//        orderId = 3;
    }
    public Order(int orderId){
        this.orderId = orderId;
    }
    //对象调用eat方法之前,类中就已经存在了sleep和eat方法了,所以不会报错
    public void eat(){
        sleep();
    }
    public void sleep(){
    }
}字节码文件:

两个构造函数,两个init

面试题1:
/**
 * static A
 * static B
 * I'm A Class
 * HelloA
 * I'm B Class
 * HelloB
 */
class HelloA {
    public HelloA() {
        System.out.println("HelloA");
    }
    {
        System.out.println("I'm A Class");
    }
    static{
        System.out.println("static A");
    }
}
class HelloB extends HelloA {
    public HelloB() {
        System.out.println("HelloB");
    }
    {
        System.out.println("I'm B Class");
    }
    static {
        System.out.println("static B");
    }
}
public class Test01 {
    public static void main(String[] args) {
        new HelloB();
    }
}面试题2:
public class Test02 {
    static int x, y,z;
    static {
        int x = 5;
        x--; //就近原则,操作的是新定义的x
    }
    static {
        x--;
    }
    public static void method(){
        y = z++ + ++z;
    }
    public static void main(String[] args) {
        System.out.println("x = " + x);
        z--; //-1
        method(); //-1 + 1 = 0 = y   z: 1
        System.out.println("result:" + (z + y + ++z));  //1 + 0 + 2 = 3
    }
}面试题3:
/**
 * Base
 * sub:100
 * sub
 * base:70
 */
class Base {
    Base(){
        method(100);
    }
    {
        System.out.println("Base");
    }
    public void method(int i){
        System.out.println("base:" + i);
    }
}
class Sub extends Base {
    Sub(){
        super.method(70);
    }
    {
        System.out.println("sub");
    }
    public void method(int i){
        System.out.println("sub:" + i);
    }
}
public class Test03 {
    public static void main(String[] args) {
        Sub s = new Sub();
    }
}
关键字:final





总结:
 
 final关键字的使用
1.final的理解:最终的
2.final可以用来修饰的结构:类、方法、变量
3.具体说明:
3.1 final修饰类:表示此类不能被继承。
    比如:String、stringBuffer、stringBuilder类
3.2 final修饰方法:表示此方法不能被重写
    比如:0bject类中的getClass()
3.3 final修饰变量:既可以修饰成员变量,也可以修饰局部变量。
    此时的"变量"其实就变成了"常量",意味着一旦赋值,就不可更改。
    3.3.1 final修饰成员变量:有哪些位置可以给成员变量赋值?
        > 显式赋值
        > 代码块中赋值
        > 构造器中赋值
    3.3.2 final修饰局部变量:一旦赋值就不能修改
    > 方法内声明的局部变量: 在调用局部变量前,一定需要赋值。而且一旦赋值,就不可更改
    > 方法的形参: 在调用此方法时,给形参进行赋值。而且一旦赋值,就不可更改
4.final与static搭配: 修饰成员变量时,此成员变量称为:全局常量。
比如:Math的PI
 
 
相关代码:
public class FinalTest {
    public static void main(String[] args) {
        E e = new E();
        System.out.println(e.MIN_SCORE);
        //编译不通过
//        e.MIN_SCORE = 1;
        E e1 = new E(10);
//        e1.LEFT = 11; //不可更改
    }
}
class E {
    //成员变量
    final int MIN_SCORE = 0; //显式赋值
    final int MAX_SCORE;
    final int LEFT;
//    final int RIGHT; //不赋值会报错
    {
//        MIN_SCORE = 1;
        MAX_SCORE = 100; //代码块赋值
    }
    {
//        MAX_SCORE = 1; //编译不通过
    }
    public E(){
        LEFT = 2;
    }
    public E(int left){
        LEFT = left;
    }
    //报错
//    public void setRight(int right){
//        RIGHT = right;
//    }
}
class F {
    public void method(){
        final int num = 10;
//        num++;//编译报错
        System.out.println(num);
    }
    public void method(final int num){
//        num++; //编译报错
        System.out.println(num);
    }
}
final class A {
}
//报错,不能被继承
//class B extends A {
//
//}
//class subString extends String {}
class C{
    public final void method(){}
}
class D extends C{
    //不能被重写
//    public void method(){
//
//    }
}
面试题:
题目1:排错
public class Something {
    public int addOne(final int x){
        return ++x; //会报错,x已被赋值了
        //return x+1;
    }
}
题目2:排错
public class Something {
    public static void main(String[] args){
        Other o = new Other();
        new Something().addOne(o);
    }
    //这个地方final修饰的是o,如果o被重新赋值了的话就会报错
    //但是i是一个变量,他是用final修饰的
    public void addOne(final Other o){
        //o= new Other();
        o.i++;
    }
}
class Other {
    public int i:
}
抽象类与抽象方法



选中这行按alt+enter键,选择实现方法(用于抽象子类重写父类的抽象方法)

弹出要实现的方法确定即可

案例:
Creature 
public abstract class Creature { //生物类
    public abstract void breath(); //呼吸
}
Person 
public abstract class Person extends Creature { //抽象类
    String name;
    int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public abstract void eat(); //抽象方法
    public abstract void sleep(); //抽象方法
}
Student 
public class Student extends Person {
    String school;
    public Student() {
    }
    public Student(String name, int age, String school) {
        super(name, age);
        this.school = school;
    }
    public void eat(){
        System.out.println("学生多吃有营养的食物");
    }
    public void sleep(){
        System.out.println("学生要保证充足的睡眠");
    }
    @Override
    public void breath() {
        System.out.println("学生应该多呼吸新鲜空气");
    }
}
Worker 
//public abstract class Worker extends Person{
//
//}
public abstract class Worker extends Person{
    @Override
    public void eat() {
        System.out.println("工人很辛苦,多吃");
    }
}
AbstractTest 
public class AbstractTest {
    public static void main(String[] args) {
        //编译不通过
//        Person p1 = new Person();
//        p1.eat();
        Student s1 = new Student();
        s1.eat();
        //抽象类不能实例化
//        Worker w1 = new Worker();
    }
}
AbstractTest1 
public class AbstractTest1 {
    //编译不通过
//    private abstract void method(){};
//    public static abstract void method(){};
}抽象类应用


多态的应用:模板方法设计模式(TemplateMethod)


总结:
 
 抽象类与抽象方法
1.案例引入
举例1:Geometric0bject-Circle-Rectangle
abstract class Geometric0bject{//几何图形
    //求面积(只能考虑提供方法的声明,而没有办法提供方法体。所以,此方法适合声明为抽象方法)
    //求周长(只能考虑提供方法的声明,而没有办法提供方法体。所以,此方法适合声明为抽象方法)
}
class Circle extends Geometric0bject {
    //求面积(必须重写(或实现)父类中的抽象方法)
    //求周长(必须重写(或实现)父类中的抽象方法)
}
举例2:Account-SavingAccount-CheckAcount
class Account{
    double balance;//余额
    //取钱 (声明为抽象方法)
    //存钱 (声明为抽象方法)
}
class SavingAccount extends Account{ //储蓄卡
    //取钱 (需要重写父类中的抽象方法)
    //存钱 (需要重写父类中的抽象方法)
}
class CheckAccount extends Account{ //信用卡
    //取钱 (需要重写父类中的抽象方法)
    //存钱 (需要重写父类中的抽象方法)
}
//......
2.abstract的概念:抽象的
3.abstract可以用来修饰:类、方法
4.具体的使用:
4.1 abstract修饰类:
    > 此类称为抽象类
    > 抽象类不能实例化。
    > 抽象类中是包含构造器的,因为子类对象实例化时,需要直接或间接的调用到父类的构造器。
    > 抽象类中可以没有抽象方法。反之,抽象方法所在的类,一定是抽象类,
        (因为需要确保这个方法不能被调用,而方法是需要通过对象来调用,这样干脆让类为抽象类,不能实例化)
4.2 abstract修饰方法
    > 此方法即为抽象方法
    > 抽象方法只有方法的声明,没有方法体。
    > 抽象方法其功能是确定的(通过方法的声明即可确定),只是不知道如何具体实现(体现为没有方法体)
    > 子类必须重写父类中的所有的抽象方法之后,方可实例化。否则,此子类仍然是一个抽象类
5.abstract不能使用的场景
5.1 abstract 不能修饰哪些结构?
属性、构造器、代码块等。
5.2 abstract 不能与哪些关键字共用? (自洽)
不能用abstract修饰私有方法、静态方法、final的方法、final的类
> 私有方法不能重写
> 避免静态方法使用类进行调用
> final的方法不能被重写
> final修饰的类不能有子类 
 
练习:
编写工资系统,实现不同类型员工(多态)的按月发放工资。如果当月出现某个 Employee对象的生日,则将该雇员的工资增加100元。 实验说明: (1)定义一个Employee类,该类包含: private成员变量name,number,birthday,其中birthday 为MyDate类的对象;提供必要的构造器 abstract方法earnings(); toString()方法输出对象的name,number和birthday。 (2)MyDate类包含: private成员变量year,month,day ;提供必要的构造器 toDateString()方法返回日期对应的字符串:xxxx年xx月xx日 (3)定义SalariedEmployee类继承Employee类,实现按月计算工资的员工处 理。该类包括:private成员变量monthlySalary; 提供必要的构造器; 实现父类的抽象方法earnings(),该方法返回monthlySalary值;toString()方法输 出员工类型信息及员工的name,number,birthday。比如:SalariedEmployee[name = '', number = '', birthday = ''] (4)参照SalariedEmployee类定义HourlyEmployee类,实现按小时计算工资的 员工处理。该类包括: private成员变量wage和hour; 提供必要的构造器; 实现父类的抽象方法earnings(),该方法返回wage*hour值; toString()方法输出员工类型信息及员工的name,number,birthday。比如:HourlyEmployee[name = '', number = '', birthday = ''] (5)定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各 类雇员对象的引用。利用循环结构遍历数组元素,输出各个对象的类 型,name,number,birthday,以及该对象生日。当键盘输入本月月份值时,如果本 月是某个Employee对象的生日,还要输出增加工资信息。 提示: //定义People类型的数组People c1[]=new People[10]; //数组元素赋值 c1[0]=new People("John","0001",20); c1[1]=new People("Bob","0002",19); //若People有两个子类Student和Officer,则数组元素赋值时,可以使父类类型的数组元素指向子类。 c1[0]=new Student("John","0001",20,85.0); c1[1]=new Officer("Bob","0002",19,90.5);TemplateMethodTest public class TemplateMethodTest { public static void main(String[] args) { BankTemplateMethod btm = new DrawMonney(); btm.process(); BankTemplateMethod btm2 = new ManageMonney(); btm2.process(); } } abstract class BankTemplateMethod { //具体方法 public void takeNumber(){ System.out.println("排队取号"); } public abstract void transact(); public void evaluate(){ System.out.println("反馈评分"); } //模板方法,把基本操作组合到一起,子类一般不能重写 public final void process(){ this.takeNumber(); this.transact(); //像个钩子,具体执行时,挂哪个类,就执行哪个子类的实现代码 this.evaluate(); } } class DrawMonney extends BankTemplateMethod { public void transact(){ System.out.println("我要取款!!!"); } } class ManageMonney extends BankTemplateMethod { public void transact(){ System.out.println("我要理财!我这里有2000万美元!!"); } } 或练习 public class TemplateTest { public static void main(String[] args) { PrintPrimeNumber p = new PrintPrimeNumber(); p.spendTime(); } } abstract class Template { //计算某段代码的执行,需要花费的时间 public void spendTime(){ long start = System.currentTimeMillis(); code(); long end = System.currentTimeMillis(); System.out.println("花费的时间为:" + (end - start)); } public abstract void code(); } class PrintPrimeNumber extends Template { public void code(){ for(int i = 2; i <= 100000; i++){ boolean isFlag = true; for(int j = 2; j <= Math.sqrt(i); j++){ if(i % j == 0){ isFlag = false; break; } } if(isFlag){ System.out.println(i); } } } }
接口(interface)










相关代码:
public class InterfaceTest {
    public static void main(String[] args) {
        System.out.println(Flyable.MIN_SPEED);
        System.out.println(Flyable.MAX_SPEED);
        //编译报错
//        Flyable.MAX_SPEED = 7800;
        Bullet b1 = new Bullet();
        b1.fly();
        b1.attack();
        //接口的多态性
        Flyable f1 = new Bullet();
        f1.fly(); //编译的时候是接口当中的方法,但是运行的时候是实现类当中的方法
    }
}
interface Flyable { //接口
    //全局常量
    public static final int MIN_SPEED = 0;
    // 可以省略public static final
    int MAX_SPEED = 7900;
    //方法可以省略public abstract声明
//    public abstract void fly();
    void fly();
}
interface Attackable { //接口
    public abstract void attack();
}
abstract class Plane implements Flyable,Attackable {
}
class Bullet implements Flyable {
    public void fly() {
        System.out.println("让子弹飞一会儿");
    }
    public void attack(){
        System.out.println("子弹可以击穿身体");
    }
}
//测试接口的继承关系
interface AA {
    void method1();
}
interface BB{
    void method2();
}
interface CC extends AA,BB{ //接口可以多继承
}
class DD implements CC {
    public void method1(){
    }
    public void method2(){
    }
}练习题:
设备连接

/**
 * 设备连接成功...
 * 打印机开始工作
 * 数据传输的细节操作...
 * 打印机结束工作
 * 设备连接成功...
 * 照相机开始工作
 * 数据传输的细节操作...
 * 照相机结束工作
 * 设备连接成功...
 * U盘开始工作
 * 数据传输的细节操作...
 * U盘开始结束工作
 * 设备连接成功...
 * 扫描仪开始工作
 * 数据传输的细节操作...
 * 扫描仪结束工作
 */
public class USBTest {
    public static void main(String[] args) {
        //1.创建接口实现类的对象
        Computer computer = new Computer();
        Printer printer = new Printer();
        computer.transferDate(printer);
        //2.创建接口实现类的匿名对象
        computer.transferDate(new Camera());
        //3.创建接口匿名实现类的对象
        USB usb1 = new USB(){
            public void start(){
                System.out.println("U盘开始工作");
            }
            public void stop(){
                System.out.println("U盘开始结束工作");
            }
        };
        computer.transferDate(usb1);
        //4.创建接口匿名实现类的匿名对象
        computer.transferDate(new USB(){
            public void start(){
                System.out.println("扫描仪开始工作");
            }
            public void stop(){
                System.out.println("扫描仪结束工作");
            }
        });
    }
}
class Computer {
    public void transferDate(USB usb){
        System.out.println("设备连接成功...");
        usb.start();
        System.out.println("数据传输的细节操作...");
        usb.stop();
    }
}
class Camera implements USB {
    @Override
    public void start() {
        System.out.println("照相机开始工作");
    }
    @Override
    public void stop() {
        System.out.println("照相机结束工作");
    }
}
class Printer implements USB {
    @Override
    public void start() {
        System.out.println("打印机开始工作");
    }
    @Override
    public void stop() {
        System.out.println("打印机结束工作");
    }
}
interface USB {
    //声明常量
    //USB的长、宽、高...
    //方法
    public abstract void start();
    void stop();
}练习2:
1、声明接口Eatable,包含抽象方法public abstract void eat(); 2、声明实现类中国人Chinese,重写抽象方法,打印用筷子吃饭 3、声明实现类美国人American,重写抽象方法,打印用刀叉吃饭 4、声明实现类印度人Indian,重写抽象方法,打印用手抓饭 5、声明测试类EatableTest,创建Eatable数组,存储各国人对象,并遍历数组,调用eat()方法
Chinese 
public class Chinese implements Eatable {
    public void eat() {
        System.out.println("中国人使用筷子吃饭");
    }
}
American 
public class American implements Eatable {
    @Override
    public void eat() {
        System.out.println("美国人使用刀叉吃饭");
    }
}
Indian 
public class Indian implements Eatable{
    @Override
    public void eat() {
        System.out.println("印度人使用手抓饭");
    }
}
public interface Eatable {
    void eat();
}
EatableTest 
public class EatableTest {
    public static void main(String[] args) {
        Eatable[] eatables = new Eatable[3];
        eatables[0] = new Chinese(); //多态性
        eatables[1] = new American();
        eatables[2] = new Indian();
        /**
         * 中国人使用筷子吃饭
         * 美国人使用刀叉吃饭
         * 印度人使用手抓饭
         */
        for (int i = 0; i < eatables.length; i++) {
            eatables[i].eat();
        }
    }
}
练习题3:
 
 定义一个接口用来实现两个对象的比较。
interface CompareObject{
    //若返回值是0,代表相等;若为正数,代表当前对象大;负数代表当前对象小
    public int compareTo(Object o);
}
定义一个Circle类,声明radius属性,提供getter和setter方法
定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。
在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
定义一个测试类InterfaceTest,创建两个ComparableCircle对象,调用compareTo方法比较两个类的半径大小。
拓展:参照上述做法定义矩形类Rectangle和ComparableRectangle类,在ComparableRectangle类
中给出compareTo方法的实现,比较两个炬形的面积大小。
 
 
CompareObject 
public interface CompareObject {
    //若返回值是 0,代表相等,若为正数,代表当前对象大;负数代表当前对象小
    public int compareTo(Object o);
}
Circle 
public class Circle {
    private double radius; //半径
    public Circle() {
    }
    public Circle(double radius) {
        this.radius = radius;
    }
    public double getRadius() {
        return radius;
    }
    public void setRadius(double radius) {
        this.radius = radius;
    }
    @Override
    public String toString() {
        return "Circle{" +
                "radius=" + radius +
                '}';
    }
}
ComparableCircle 
public class ComparableCircle extends Circle implements CompareObject {
    public ComparableCircle() {
    }
    public ComparableCircle(double radius) {
        super(radius);
    }
    //根据对象半径的大小,比较对象的大小
    @Override
    public int compareTo(Object o) {
        if(this == o) {
            return 0;
        }
        if(o instanceof ComparableCircle) {
            ComparableCircle c = (ComparableCircle)o;
            // 错误的
//            return (int)(this.getRadius() - c.getRadius());
            //正确的写法1:
//            if(this.getRadius() > c.getRadius()) {
//                return 1;
//            }else if(this.getRadius() < c.getRadius()){
//                return -1;
//            }else {
//                return 0;
//            }
            //正确的写法2:
            return Double.compare(this.getRadius(), c.getRadius());
        }else {
            return 2; //如果输入的类型不匹配,则返回2
//            throw new RuntimeException("输入的类型不匹配");
        }
    }
}
InterfaceTest 
public class InterfaceTest {
    public static void main(String[] args) {
        ComparableCircle c1 = new ComparableCircle(2.3);
        ComparableCircle c2 = new ComparableCircle(5.3);
        int compareValue = c1.compareTo(c2);
        if(compareValue > 0){
            System.out.println("c1对象大");
        }else if(compareValue < 0){
            System.out.println("c2对象大");
        }else{
            System.out.println("c1和c2一样大");
        }
    }
}接口的应用:代理模式(Proxy)






总结:
 
 接口的使用
1.接口的理解:接口的本质是契约、标准、规范,就像我们的法律一样。制好后大家都要遵守
2.定义接口的关键字:interface
3.接口内部结构的说明:
    > 可以声明:
        属性:必须使用public static final修饰
        方法:jdk8之前:声明抽象方法,修饰为public abstract
            jdk8:声明静态方法、默认方法
            jdk9:声明私有方法
    > 不可以声明: 构造器、代码块等
4.接口与类的关系:实现关系
5.格式: class A extends SuperA implements B,C{}
A相较于SuperA来讲,叫做子类
A相较于B,C来讲,叫做实现类。
6.满足此关系之后,说明:
> 类可以实现多个接口。
> 类针对于接口的多实现,一定程度上就弥补了类的单继承的局限性。
> 类必须将实现的接口中的所有的抽象方法都重写(或实现),方可实例化。否则,此实现类必须声明为抽象类。
7.接口与接口的关系: 继承关系,且可以多继承
8.接口的多态性: 接口名 变量名 = new 实现类对象;
             // 父类 变量名 = new 子类对象; 类的多态性
9.面试题:区分抽象类和接口
> 共性:都可以声明抽象方法
    都不能实例化
> 不同:① 抽象类一定有构造器。接口没有构造器
      ② 类与类之间继承关系,类与接口之间是实现关系,接口与接口之间是多继承关系 
 
相关代码 :
CompareA 
public interface CompareA {
    //属性:声明为public static final
    //方法:jdk8之前,只能声明抽象方法
    //方法:jdk8中:静态方法
    public static void method1(){
        System.out.println("CompareA:北京");
    }
    //方法:jdk8中:默认方法
//    public void method3(); //这种写法是抽象方法,不是抽象方法就需要抽象体
    public default void method2(){
        System.out.println("CompareA:上海");
    };
    public default void method3(){
        System.out.println("CompareA:广州");
    };
    public default void method4(){
        System.out.println("CompareA:深圳");
    };
    //jdk9新特性:定义私有方法
    private void method5(){
        System.out.println("我是接口中定义的私有方法");
    }
}
CompareB 
public interface CompareB {
    public default void method3(){
        System.out.println("CompareB: 广州");
    }
}
SuperClass 
public class SuperClass {
    public void method4() {
        System.out.println("SuperClass:深圳");
    }
}
SubClassTest 
public class SubClassTest {
    public static void main(String[] args) {
        //知识点1:接口中声明的静态方法只能被接口来调用,不能使用期实现类进行调用
        CompareA.method1();
//        SubClass.method1(); //编译不通过
        //默认方法涉及到造对象,重写之后调用的是重写之后的方法
        //知识点2:接口中声明的默认方法可以被类继承,实现类在没有重写此方法的情况下,默认调用接口中声明的
        //默认方法,如果实现类重写了此方法,则调用的是自己重写的方法
        SubClass s1 = new SubClass();
        s1.method2();
        //知识点3:类实现了两个接口,而两个接口中定义了同名同参数的默认方法,则实现类在没有重写此两个接口
        //默认方法的情况下,或报错,--->接口冲突
        //要求:此时实现类必须要重写接口中定义的同名同参数的方法
        s1.method3();
        //知识点4:子类(或实现类)继承了父类并实现了接口,父类和接口中声明了同名同参数的方法,(其中,接口中的方法
        //是默认方法)。默认情况下,子类(或实现类)在没有重写此方法的情况下,调用的是父类中的方法。---> 类优先原则
        /**
         * CompareA:北京
         * SubClass:上海
         * SubClass:广州
         * SuperClass:深圳 ---> SubClass:深圳(子类重写之后)
         */
        s1.method4();
    }
}
SubClass 
public class SubClass extends SuperClass implements CompareA, CompareB {
    @Override
    public void method2() {
        System.out.println("SubClass:上海");
    }
    @Override
    public void method3() {
        System.out.println("SubClass:广州");
    }
    public void method4() {
        System.out.println("SubClass:深圳");
    }
    public void method(){
        //知识点5:如何在子类(或实现类)中调用父类或接口中重写的方法
        method4(); //调用自己类中的方法
        super.method4();
        method3(); //调用自己类中的方法
//        CompareA.method1(); //静态方法可以这样调用,不是静态的方法按照下面的方式调用
        CompareA.super.method3(); //调用接口CompareA中的默认方法
        CompareB.super.method3(); //调用接口CompareB中的默认方法
    }
}
类的成员之五:内部类

内部类生成的文件通过 $内部类名 来表示






代码示例:
public class OuterClassTest {
    public static void main(String[] args) {
        //1.创建Person的静态的成员内部类的实例
        Person.Dog dog = new Person.Dog();
        dog.eat();
        //2.创建Person的非静态的成员内部类的实例
//        Person.Bird bird = new Person.Bird(); //报错
         Person p1 = new Person();
         Person.Bird bird = p1.new Bird(); //正确的
         bird.eat();
         bird.show("黄鹂");
         bird.show1();
    }
}
class Person { //外部类
    String name = "Tom";
    int age = 1;
    //静态的成员内部类
    static class Dog{
        public void eat() {
            System.out.println("狗吃骨头");
        }
    }
    //非静态的成员内部类
    class Bird{
        String name = "啄木鸟";
        public void eat(){
            System.out.println("鸟吃虫子");
        }
        public void show(String name){
            System.out.println("age = " + age); //age = 1 省略了Person.this
            System.out.println("name = " + name); //name = 黄鹂
            System.out.println("name = " + this.name); //name = 啄木鸟
            System.out.println("name = " + Person.this.name); //name = Tom
        }
        public void show1(){
            eat(); //鸟吃虫子
            this.eat(); //鸟吃虫子
            Person.this.eat(); //人吃饭
        }
    }
    public void eat(){
        System.out.println("人吃饭");
    }
    public void method(){
        //局部内部类
        class innerClass1{
        }
    }
    public Person(){
        //局部内部类
        class innerClass1{
        }
    }
    {
        //局部内部类
        class innerClass1{
        }
    }
}代码示例2:
public class OuterClassTest1 {
    //说明:局部内部类的使用
    public void method1(){
        //局部内部类
        class A{
            //可以声明属性、方法等
        }
    }
    //开发中的场景
    public Comparable getInstance(){
        //提供了实现了Comparable接口的类
        //方式1:提供了接口的实现类的对象
//        class MyComparable implements Comparable{
//
//            @Override
//            public int compareTo(Object o) {
//                return 0;
//            }
//        }
//        MyComparable m = new MyComparable();
//        return m;
        //方式1:提供了接口的实现类的匿名对象
//        class MyComparable implements Comparable{
//
//            @Override
//            public int compareTo(Object o) {
//                return 0;
//            }
//        }
//        return new MyComparable();
        //方式2:提供了接口的匿名实现类的对象
        //后面的大括号表示实现类
//        Comparable c = new Comparable() {
//            @Override
//            public int compareTo(Object o) {
//                return 0;
//            }
//        };
//        return c;
        //方式3:提供了接口的匿名实现类的匿名对象
        return new Comparable(){
            @Override
            public int compareTo(Object o) {
                return 0;
            }
        };
    }
}
代码示例3:
public class OuterClassTest2 {
    public static void main(String[] args) {
        SubA a = new SubA();
        a.method();
        //举例1:提供了接口匿名实现类的对象
        A a1 = new A(){
            public void method() {
                System.out.println("匿名实现类重写的方法method()");
            }
        };
        a1.method();
        //举例2:提供了接口匿名实现类的匿名对象
        new A(){
            public void method() {
                System.out.println("匿名实现类重写的方法method()");
            }
        }.method();
        //举例3:
        SubB s1 = new SubB();
        s1.method1();
        //举例4:提供了继承于抽象类的匿名子类的对象
        B b = new B() {
            @Override
            public void method1() {
                System.out.println("继承于抽象类的子类调用的方法");
            }
        };
        b.method1();
        System.out.println(b.getClass()); //class com.atguigu09.inner.OuterClassTest2$3
        System.out.println(b.getClass().getSuperclass()); //class com.atguigu09.inner.B
        //举例5:
        new B(){
            @Override
            public void method1() {
                System.out.println("继承于抽象类的子类调用的方法1");
            }
        }.method1();
        //举例6:
        C c = new C();
        c.method2();
        //举例7:提供了一个继承于C的匿名子类的对象
//        C c1 = new C(){};
        C c1 = new C(){
            public void method2() {
                System.out.println("SubC");
            }
        };
        c1.method2();
//        System.out.println(c.getClass());//class com.atguigu09.inner.C
//        System.out.println(c1.getClass().getSuperclass());//class com.atguigu09.inner.C
    }
}
interface A{
    public void method();
}
class SubA implements A{
    public void method(){
        System.out.println("SubA");
    }
}
abstract class B{
    public abstract void method1();
}
class SubB extends B{
    public void method1(){
        System.out.println("SubB");
    }
}
class C{
    public void method2(){
        System.out.println("C");
    }
}
练习1:
编写一个匿名内部类,它继承Object,并在匿名内部类中,声明一个方法public void test()打印尚硅谷。 请编写代码调用这个方法。
public class ObjectTest {
    public static void main(String[] args) {
//        SubObject sub1 = new SubObject();
//        sub1.test();
        //提供一个继承于Object的匿名子类的匿名对象
        new Object(){
            public void test(){
                System.out.println("尚硅谷");
            }
        }.test();
    }
}
class SubObject extends Object{
    public void test(){
        System.out.println("尚硅谷");
    }
}
native关键字的理解:

枚举类enum


单例模式当中有饿汉式与懒汉式
总结:
 
 枚举类的使用
1.枚举类的理解:枚举类型本质上也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。
2.举例:
- 星期:Monday(星期一)......Sunday(星期天)
- 性别:Man(男)、Woman(女)
- 月份:January(1月)......December(12月)
- 季节:Spring(春节)......Winter(冬天)
- 三原色:red(红色)、green(绿色)、blue(蓝色)
- 支付方式:Cash(现金)、WechatPay(微信)、Alipay(支付宝)、BankCard(银行卡)、Creditcard(信用卡)
- 就职状态:Busy(忙碌)、Free(空闲)、Vocation(休假)、Dimission(离职)
- 订单状态:Nonpayment(未付款)、Paid(已付款)、Fulfilled(已配货)、Delivered(已发货)、checked(已确认收货)、Return(退货)、Exchange(换货)、Cancel(取消)
- 线程状态:创建、就绪、运行、阻塞、死亡
3.开发中的建议:
> 开发中,如果针对于某个类,其实例是确定个数的,则推荐将此类声明为枚举类
> 如果枚举类的实例只有一个,则可以看做是单例的实现方式。
4.JDK5.0 之前如何自定义枚举类(了解)
见代码
5.JDK5.0中使用enum定义枚举类
见代码
6.Enum中的常用方法:
6.1 使用enum关键字定义的枚举类,默认其父类是java.lang.Enum类
    使用enum关键字定义的枚举类,不要再显示的定义其父类。否则报错
6.2 熟悉Enum类中常用的方法
    string toString():默认返回的是常量名(对象名),可以继续手动重写该方法!
    (关注)static 枚举类型[] valves():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值,是一个静态方法
    (关注)static 枚举类型 value0f(String name):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的"名字"。如不是,会有运行时异常:IllegalArgumentException。
    String name():得到当前枚举常量的名称。建议优先使用toString()。
    int ordinal():返回当前枚举常量的次序号,默认从0开始
7.枚举类实现接口的操作
    情况1:枚举类实现接口,在枚举类中重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是同一个方法。
    情况2:让枚举类的每一个对象重写接口中的抽象方法。当通过不同的枚举类对象调用此方法时,执行的是不同的实现的方法。
 
 
相关代码1:
public class SeasonTest {
    public static void main(String[] args) {
//        Season.AUTUMN = null; //报错
        System.out.println(Season.SPRING);
        System.out.println(Season.SUMMER.getSeasonName());
        System.out.println(Season.SUMMER.getSeasonDesc());
    }
}
//jdk5.0之前定义的枚举方式
class Season{
    //2.声明当前类的对象的实例变量,使用private final修饰
    private final String seasonName; //季节的名称
    private final String seasonDesc; //季节的描述
    //1.私有化类的构造器
    private Season(String seasonName, String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    //3.提供实例变量的get方法
    public String getSeasonName(){
        return seasonName;
    }
    public String getSeasonDesc(){
        return seasonDesc;
    }
    //4.创建当前类的实例,使用public static final修饰
    public static final Season SPRING = new Season("春天", "春暖花开");
    public static final Season SUMMER = new Season("夏天", "夏日炎炎");
    public static final Season AUTUMN = new Season("秋天", "秋高气爽");
    public static final Season WINTER = new Season("冬天", "白雪皑皑");
    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}
相关代码2:
public class SeasonTest1 {
    public static void main(String[] args) {
//        System.out.println(Season1.SPRING.getClass()); //class com.atguigu10._enum.Season1
//        System.out.println(Season1.SPRING.getClass().getSuperclass()); //class java.lang.Enum
//        System.out.println(Season1.SPRING.getClass().getSuperclass().getSuperclass()); //class java.lang.Object
        //测试方法
        //1.toString()
        System.out.println(Season1.SPRING); //SPRING(toString()重写之前)
        //2.name()
        System.out.println(Season1.SPRING.name()); //SPRING
        //3.values()
        Season1[] values = Season1.values();
        /**
         * Season1{seasonName='春天', seasonDesc='春暖花开'}
         * Season1{seasonName='夏天', seasonDesc='夏日炎炎'}
         * Season1{seasonName='秋天', seasonDesc='秋高气爽'}
         * Season1{seasonName='冬天', seasonDesc='白雪皑皑'}
         */
        for(int i=0; i<values.length; i++){
            System.out.println(values[i]);
        }
        //4.valueOf(String objName):再返回当前枚举类中名称为objName的枚举对象
        //如果枚举类不存在objName名称的对象,则报错
        String objName = "WINTER";
//        objName = "WINTER1"; //报错IllegalArgumentException
        Season1 season1 = Season1.valueOf(objName);
        System.out.println(season1);
        //5.ordinal()
        System.out.println(Season1.AUTUMN.ordinal()); //2
        //通过枚举类的对象调用重写后的接口中的方法
        Season1.AUTUMN.show();
    }
}
interface Info{
    void show();
}
//jdk5.0中使用enum关键字定义枚举类
enum Season1 implements Info{
    //1.必须在枚举类的开头声明多个对象,对象之间使用,隔开
    SPRING("春天", "春暖花开"),
    SUMMER("夏天", "夏日炎炎"),
    AUTUMN("秋天", "秋高气爽"),
    WINTER("冬天", "白雪皑皑");
    //2.声明当前类的对象的实例变量,使用private final修饰
    private final String seasonName; //季节的名称
    private final String seasonDesc; //季节的描述
    //3.私有化类的构造器
    private Season1(String seasonName, String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    //3.提供实例变量的get方法
    public String getSeasonName(){
        return seasonName;
    }
    public String getSeasonDesc(){
        return seasonDesc;
    }
    @Override
    public String toString() {
        return "Season1{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
    @Override
    public void show() {
        System.out.println("这是一个季节");
    }
}
改进2
public class SeasonTest2 {
    public static void main(String[] args) {
        Season2[] values = Season2.values();
        for(int i = 0; i < values.length; i++){
//            System.out.println(values[i]);
            values[i].show();
        }
    }
}
interface Info1{
    void show();
}
//jdk5.0中使用enum关键字定义枚举类
enum Season2 implements Info1{
    //1.必须在枚举类的开头声明多个对象,对象之间使用,隔开
    SPRING("春天", "春暖花开"){
        public void show(){
            System.out.println("春天在哪里?");
        }
    },
    SUMMER("夏天", "夏日炎炎"){
        public void show(){
            System.out.println("宁静的夏天");
        }
    },
    AUTUMN("秋天", "秋高气爽"){
        public void show(){
            System.out.println("秋意浓");
        }
    },
    WINTER("冬天", "白雪皑皑"){
        public void show(){
            System.out.println("大约在冬季");
        }
    };
    //2.声明当前类的对象的实例变量,使用private final修饰
    private final String seasonName; //季节的名称
    private final String seasonDesc; //季节的描述
    //3.私有化类的构造器
    private Season2(String seasonName, String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    //3.提供实例变量的get方法
    public String getSeasonName(){
        return seasonName;
    }
    public String getSeasonDesc(){
        return seasonDesc;
    }
    @Override
    public String toString() {
        return "Season1{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}
就职状态代码:
Employee 
public class Employee {
    private String name;
    private int age;
    private Status status;
    public Employee() {
    }
    public Employee(String name, int age, Status status) {
        this.name = name;
        this.age = age;
        this.status = status;
    }
    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 Status getStatus() {
        return status;
    }
    public void setStatus(Status status) {
        this.status = status;
    }
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", status=" + status +
                '}';
    }
}
枚举:
public enum Status {
    BUSY,FREE,VOCATION,DIMISSION;
}
EmployeeTest 
public class EmployeeTest {
    public static void main(String[] args) {
        Employee e1 = new Employee("Tom", 21, Status.BUSY);
        System.out.println(e1); //Employee{name='Tom', age=21, status=BUSY}
    }
}案例:使用枚举类实现单例模式
public class BnakTest1 {
    public static void main(String[] args) {
//        Bank1.instance = null; //final可以用但不能修改
        System.out.println(GirlFriend.XIAL_LI); //XIAL_LI
    }
}
//jdk5.0之前的使用枚举类定义单例模式
class Bank1 {
    //饿汉式
//    private Bank1(){}
//    private static Bank1 instance = new Bank1();
//    public static Bank1 getInstance(){
//        return instance;
//    }
    //枚举类没有通过方法调用,而是直接通过类来调用
    private Bank1(){}
    private static final Bank1 instance = new Bank1();
}
//jdk5.0使用enum关键字定义枚举类的方式定义单例模式
enum Bank2{
    CPB;
}
enum GirlFriend{
//    public static final GirlFriend XIAL_LI = new GirlFriend(20); //之前写法
    XIAL_LI(20);
    private final int age;
    private GirlFriend(int age){
        this.age = age;
    }
}案例:
案例拓展:颜色枚举类(使用enum声明) (1)声明颜色枚举类Color: - 声明final修饰的int类型的属性red,green,blue - 声明final修饰的String类型的属性description - 声明有参构造器Color(int red,int green,int blue,String description) - 创建7个常量对象:红、橙、黄、绿、青、蓝、紫, - 重写toString方法,例如:RED(255,0,0)->红色 (2)在测试类中,使用枚举类,获取绿色对象,并打印对象。 提示: - 7个常量对象的RGB值如下: 红:(255,0,0) 橙:(255,128,0) 黄:(255,255,0) 绿:(0,255,0) 青:(0,255,255) 蓝:(0,0,255) 紫:(128,0,255) 7个常量对象名如下 RED, ORANGE,YELLOW, GREEN,CYAN, BLUE,PURPLEpublic class ColorTest { public static void main(String[] args) { System.out.println(Color.BLUE); } } enum Color { RED(255,0,0,"红色"), ORANGE(255,128,0,"橙色"), YELLOW(255,255,0,"黄色"), GREEN(0,255,0,"绿色"), CYAN(0,255,255,"青色"), BLUE(0,0,255,"蓝色"), PURPLE(128,0,255,"紫色"); private final int red; private final int green; private final int blue; private final String description; //颜色的描述 Color(int red, int green, int blue, String description) { this.red = red; this.green = green; this.blue = blue; this.description = description; } public int getRed() { return red; } public int getGreen() { return green; } public int getBlue() { return blue; } public String getDescription() { return description; } @Override public String toString() { // return name()+ "(" + red + "," + green + "," + blue + ")" + "--->" + description; return super.toString()+ "(" + red + "," + green + "," + blue + ")" + "--->" + description; } }
annotation注解的使用








`@SuppressWarnings`:抑制编译器警告 
移动到元素上,选择更多操作


结果如下: @SuppressWarnings("unused") int num = 10;

JUnit单元测试




怎么添加单元测试包,通过+号选择库(library)

务必选择编译

就可以为当前模块(module)添加单元测试(junit)
也可以通过选中当前@Test这个测试类,按住alt+enter回车键,在有网的情况下下载包
默认情况下,单元测试方法中使用Scanner失效。如何解决?
在单元测试里面如果没有做什么配置,在这个地方输入什么都无法显示


如果不想是只读的,输入的数值可以显示出来,在help里面选择编辑自定义虚拟机选项

在这个文件中将这一句话加上:-Deditable.java.test.console=true

之后在文件地方选择使缓存失效

点击重启,或者直接关闭idea,重新打开也可

此时再输入数值就可以正常显示了

结果显示:

如何将将单元测试设置成一个模板?


使用模板,在光标出输入需要输入的值

总结和相关代码:
JUnit单元测试的使用 1.需要导入的jar包: junit-4.12.jar hamcrest-core-1.3.jar 2.导入步骤 见课件 3.创建单元测试类,进行测试 见代码 4.(重点关注)要想能正确的编写单元测试方法,需要满足: - 所在的类必须是public的,非抽象的,包含唯一的无参构造器。 - @Test标记的方法本身必须是public,非抽象的,非静态的,void无返回值,()无参数的。 5.默认情况下,单元测试方法中使用Scanner失效。如何解决? 6.大家可以将单元测试设置成一个模板?public class JunitTest { //单元测试类 public static void main(String[] args) { //静态方法调用非静态方法需要进行测试 JunitTest test = new JunitTest(); System.out.println(test.number); test.method(); } int number = 10; @Test public void test1() { //单元测试方法 System.out.println("Hello"); } @Test public void test2() { System.out.println("Hello1"); System.out.println("number = " + number); method(); int num = showInfo("China"); System.out.println(num); } public void method() { System.out.println("method()......"); } public int showInfo(String info){ System.out.println(info); return 10; } @Test public void test3() { Scanner sc = new Scanner(System.in); System.out.println("请输入一个数值"); int num = sc.nextInt(); System.out.println(num); for(int i = 1; i <= num; i++){ System.out.println(i); } } @Test public void test4(){ System.out.println("Hello4"); } @Test public void test5(){ System.out.println("Hello5"); } }
包装类(Wrapper)的使用



基本类型、包装类与String类间的转换



字节码文件可以体现出自动装箱与自动拆箱的过程

包装类缓存对象

面试题1:
public class InterviewTest1 {
    public static void main(String[] args) {
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j); // false
        //底层都会调用Integer的valueOf()
        //这个地方取得值是里面已经new好的Integer数组里面的对象,cache数组中每一个位置都是一个new Integer()对象,
        //所以他们的地址值都是相同的,都是取的cache数组中的第129位
        Integer m = 1; //自动装箱
        Integer n = 1;
        System.out.println(m == n); //true
        //根据valueOf的源码可知,这个地方的128不在[-128,127]范围内,所以是new Integer(i)的一个对象出来
        Integer x = 128;
        Integer y = 128;
        System.out.println(x == y); //false
    }
}cache数组长度是256,循环,cache数组[第一位是-128,第二位是-127.....一直到127]为止

用自动装箱的方式,在这个范围内用==判断的全都是true,出了这个范围是false
面试题2:
public class InterviewTest2 {
    public static void main(String[] args) {
        //题目1:
        int i = 10;
        double d = 10.2;
        System.out.println(i == d); //false
        //题目2:
        Integer i1 = 10;
        Double d1 = 10.2;
//        System.out.println(i1 == d1); //报错,==可以比较引用类型的地址,但是需要时同一类型
        //题目3:会进行拆箱,m就会转成int类型的,装箱会成为不同引用类型,会报错
        Integer m = 1000; //1000先装箱,比较时拆箱
        double n = 1000;
        System.out.println(m == n); //true
        //题目4:
        Integer x = 1000;
        int y = 1000;
        System.out.println(x == y); // true
    }
}
int(i)类型转换成(to)成double类型(d) i2d

面试题3:
public class InterviewTest3 {
    public static void main(String[] args) {
        //这个地方的比较有一个类型兼容的问题,所以输出结果是1.0
        Object o1 = true ? new Integer(1) : new Double(2.0);
        System.out.println(o1); //1.0
        Object o2;
        if(true)
            o2 = new Integer(1);
        else
            o2 = new Double(2.0);
        System.out.println(o2); //1
    }
}总结:
 
 包装类的使用
1.为什么要使用包装类?
为了使得基本数据类型的变量具备引用数据类型变量的相关特征(比如:封装性、继承性、多态性),我们给各个基本数据
类型的变量都提供了对应的包装类。
2.(掌握)基本数据类型对应的包装类类型
    byte -> Byte
    short -> Short
    int -> Integer
    long -> Long
    float -> Float
    double ->Double
    char -> Character
    boolean -> Boolean
3.掌握基本数据类型 与 包装类之间的转换。
    3.1 为什么需要转换
        > 一方面,在有些场景下,需要使用基本数据类型对应的包装类的对象。此时就需要将基本数据类型的变量转换为
            包装类的对象。比如:ArrayList的add(Object obj);Object类的equals(Object obj)
        > 对于包装类来讲,既然我们使用的是对象,那么对象是不能进行+ - * /等运算的。为了能够进行这些运算,就
            需要将包装类的对象转换为基本数据类型的变量。
    3.2 如何转换:
        (装箱)基本数据类型 ---> 包装类: ① 使用包装类的构造器 ② (建议)调用包装类的valueOf(xxxxx)
        (拆箱)包装类 ---> 基本数据类型: 调用包装类的xxxValue()
    注意:原来使用基本数据类型变量的位置,改成包装类以后,对于成员变量来说,其默认值变化了!
    jdk5.0新特性:自动装箱、自动拆箱。
4.String 与 基本数据类型、包装类之间的转换。
    基本数据类型、包装类---> String类型: ① String类型:调用String的重载的静态方法value0f(xxxxx); ② 基本数据类型的变量 + ""
    String类型 ---> 基本数据类型、包装类:调用包装类的静态方法:parseXxx()
 
 
相关代码:代码练习
public class WrapperTest {
    /**
     * 基本数据类型 ---> 包装类: ① 使用包装类的构造器 ② (建议)调用包装类的value0f(xxx xx)
     * 包装类 ---> 基本数据类型: 调用包装类的xxxValue()
     * jdk5.0新特性:自动装箱、自动拆箱。
     */
    @Test
    public void test4(){
        //自动装箱: 基本数据类型--->包装类
        int i1 = 10;
        Integer ii1 = i1;//自动装箱
        System.out.println(ii1.toString());
        Integer ii2 = i1 + 1; //自动装箱
        Boolean bb1 = true;//自动装箱
        Float f1 = 12.3F;//自动装箱
        //自动拆箱:包装类---> 基本数据类型
        int i2 = ii1; //自动拆箱
        boolean b1 = bb1; //自动拆箱
    }
    @Test
    public void test3(){
        Account account = new Account();
        System.out.println(account.isFlag1); //false
        System.out.println(account.isFlag2); //null
        System.out.println(account.balance1); //0.0
        System.out.println(account.balance2); //null
    }
    @Test
    public void test2(){
        Integer ii1 = new Integer(10);
        int i1 = ii1.intValue();
        i1 = i1 + 1;
        Float ff1 = new Float(12.3F);
        float f1 = ff1.floatValue();
        Boolean bb1 = Boolean.valueOf(true);
        Boolean b1 = bb1.booleanValue();
    }
    @Test
    //基本数据类型 ---> 包装类: ① 使用包装类的构造器 ② (建议)调用包装类的value0f(xxx xx)
    public void test1(){
        int i1 = 10;
        Integer ii1 = new Integer(i1);
        System.out.println(ii1.toString()); //10
        float f1 = 12.3F;
        f1 = 32.2f;
        Float ff1 = new Float(f1);
        System.out.println(ff1.toString()); //32.2
        String s1 = "32.1";
        Float ff2 = new Float(s1);
//        s1 = "abc";
//        Float ff3 = new Float(s1); //报异常:NumberFormatException
        boolean b1 = true;
        Boolean bb1 = new Boolean(b1);
        System.out.println(bb1);//true
        //Boolean这块只要长的跟true不一样就是false了
        String s2 = "false";
        s2 = "False123";
        s2 = "TrUe"; //忽略大小写
        Boolean bb2 = new Boolean(s2);
        System.out.println(bb2); //false --> true
        //推荐使用
        int i2 = 10;
        Integer ii2 = Integer.valueOf(i2);
        Boolean b2 = Boolean.valueOf(true);
        Float f2 = Float.valueOf(12.3F);
    }
}
class Account{
    boolean isFlag1;
    Boolean isFlag2; //null 包装类
    double balance1; //0.0
    Double balance2; //null 包装类 0.0可以理解成这个对象被初始化了
}
相关代码2:
public class WrapperTest1 {
    /**
     * 基本数据类型、包装类---> ① String类型:调用String的重载的静态方法value0f(xxxxx); ② 基本数据类型的变量 + ""
     * String类型 ---> 基本数据类型、包装类:调用包装类的静态方法:parseXxx()
     */
    @Test
    public void test2(){
        String s1 = "123";
        int i1 = Integer.parseInt(s1);
        System.out.println(i1 + 10);
        String s2 = "true";
        boolean b1 = Boolean.parseBoolean(s2);
        //特别的
//        String s3 = "123a";
//        int i2 = Integer.parseInt(s3); //报错NumberFormatException
    }
    @Test
    public void test1(){
        //方式1:① String类型:调用String的重载的静态方法value0f(xxxxx); ② 基本数据类型的变量 + ""
        int i1 = 10;
        String str1 = String.valueOf(i1);
        System.out.println(str1); //"10"
        boolean b1 = true;
        Boolean b2 = b1;
        String str2 = String.valueOf(b1);
        String str3 = String.valueOf(b2);
        //方式2:基本数据类型的变量 + ""
        String str4 = i1 + "";
        String str5 = b1 + "";
    }
}
练习题:
 
 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。而向量类java.util.Vector可以根据需要动
1、创建Vector对象:Vector v=new Vector();
2、给向量添加元素:v.addElement(Object obj);//obj必须是对象
3、取出向量中的元素:Object obj=v.elementAt(0);
    注意第一个元素的下标是0,返回值是0bject类型的。
4、计算向量的长度:v.size();
5、若与最高分相差10分内:A等;20分内:B等;30分内:C等;其它:D等
 
 
package com.atguigu12.wrapper.exer;
import java.util.Scanner;
import java.util.Vector;
/**
 * ClassName: ScoreTest
 * Package: com.atguigu12.wrapper.exer
 * Description:
 *
 * @Author: shkstart
 * @Create 2025-03-25 23:46
 * @Version: 1.0
 */
public class ScoreTest {
    public static void main(String[] args) {
        //1.创建Vector对象:Vector v= new Vector();
        Vector v= new Vector();
        Scanner scanner = new Scanner(System.in);
        int maxScore = 0; //记录最高分
        //2.从键盘中获取学生成绩,存放到v中(以负数代表输入结果)
        while(true){
            System.out.print("请输入学生成绩(以负数代表输入结束):");
            int intScore =  scanner.nextInt();
            if(intScore < 0){
                break;
            }
//            //装箱:int ---> Integer对象
//            Integer score = Integer.valueOf(intScore);
//            //添加学生成绩到容器v中
//            v.addElement(score);
            //jdk5.0之后,自动装箱
            v.addElement(intScore);
            //3.获取学生成绩的最大值
            if(maxScore < intScore){
                maxScore = intScore;
            }
        }
        System.out.println("最高分:" + maxScore);
        //4.依次获取v中的每个学生成绩,与最高分进行比较,获取学生等级,进行输出
        for(int i = 0; i < v.size(); i++){
            Object objScore = v.elementAt(i);
            //方式1:
//            Integer integerScore = (Integer)objScore;
//            //拆箱
//            int score = integerScore.intValue();
            //方式2:自动拆箱
            int score = (Integer)objScore;
            char grade = ' ';
            if(maxScore - score <= 10){
                grade = 'A';
            }else if(maxScore - score <= 20){
                grade = 'B';
            }else if(maxScore - score <= 30){
                grade = 'C';
            }else {
                grade = 'D';
            }
            System.out.println("student " + i + " score: " + score + " grade: " + grade);
        }
        scanner.close();
    }
}
ctrl+fn+f12或ctrl+f12在当前文件进行搜索,搜索内容可以直接输入

IDEA断点调试


Person p1 = new Person(3); System.out.println(p1.toString());toString()没有重写之前打印的是地址,对于引用数据类型来说,重写之后,打印的是重写之后的方法
总结:
 
 IDEA中调试程序
1.为什么需要Debug?
编好的程序在执行过程中如果出现错误,该如何查找或定位错误呢?简单的代码直接就可以看出来,
但如果代码比较复杂,就需要借助程序调试工具(Debug)来查找错误了。
2. Debug的步骤
    1、添加断点
    2、启动调试
    3、单步执行
    4、观察变量和执行流程,找到并解决问题
 
 
Description:演示1:行断点,测试debug各个常见操作按钮
Description: 演示2: 方法断点
Description:演示3:字段断点
Description:演不4:条件断点

Description:演示7:强制结束
复习:


//底层都会调用Integer的valueOf() //这个地方取得值是里面已经new好的Integer数组里面的对象,cache数组中每一个位置都是一个new Integer()对象, //所以他们的地址值都是相同的,都是取的cache数组中的第129位 //享元设计模式 Integer m = 1; //自动装箱 Integer n = 1; System.out.println(m == n); //true










![[unity 点击事件] 区域响应点击事件,排除子节点区域,Raycast Target 应用](https://i-blog.csdnimg.cn/direct/53f40f6b699e4dd1afd76a5d403af840.png)








