uacs2024

导航

Java基础语法1

Scanner输入

import java.util.Scanner;

public class ScannerDemo1 {
    public static void main(String[] args) {
        //用户键盘输入名字和年龄,然后打印出来
        //1.创建一个扫描器对象,用于接收键盘数据
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入名字:");
        String name = sc.next();//让程序在这一行暂停,等到用户输入一个字符串按了回车键,然后把用户输入的内容赋值给name变量
        System.out.println("请输入年龄:");
        int age = sc.nextInt();  // nextDouble()读取下一个双精度浮点数
        System.out.println("name:" + name + ",age:" + age);
    }
}

n位验证码

public class Demo1 {
    public static void main(String[] args) {
        System.out.println(getVerificationCode(4));
        System.out.println(getVerificationCode(6));
    }

    public static String getVerificationCode(int length){
        String code = "";
        for(int i = 0; i < length; i++){
            int type = (int)(Math.random() * 3);//0,1,2
            switch (type){
                case 0://数字
                    int num = (int)(Math.random() * 10);
                    code += num;
                    break;
                case 1://大写字母
                    int upper = (int)(Math.random() * 26);
                    code += (char)(upper + 'A');
                    break;
                case 2://小写字母
                    int lower = (int)(Math.random() * 26);
                    code += (char)(lower + 'a');
                    break;
            }
        }
        return code;
    }
}

JavaBean

如果为类创造了有参构造器,那么编译器就不会再创建无参构造器。如果还想使用无参构造器,那么需要自己创建一个无参构造器。
变量存在栈里面,存储对象的地址指向对象,对象存在堆里面,堆里面存储类的地址,指向类,类存在方法区里面,方法区里的方法需要调到栈中执行,执行完之后就清理掉。

Student.java

public class Student {
    //1.私有成员变量
    private String name;
    private int age;
    private double chinese;
    private double math;

    //提供无参数的构造方法
    public Student() {}

    //提供有参数的构造方法
    public Student(String name, int age, double chinese, double math) {
        this.name = name;
        this.age = age;
        this.chinese = chinese;
        this.math = math;
    }

    //提供公开的getter和setter方法
    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 double getChinese() {
        return chinese;
    }
    public void setChinese(double chinese) {
        this.chinese = chinese;
    }
    public double getMath() {
        return math;
    }
    public void setMath(double math) {
        this.math = math;
    }
}

StudentOperator.java

public class StudentOperator {
    private Student s;
    public StudentOperator() {}
    public StudentOperator(Student s) {
        this.s = s;
    }
    public void printScore() {
        System.out.println("姓名:" + s.getName());
        System.out.println("年龄:" + s.getAge());
        System.out.println("语文成绩:" + s.getChinese());
        System.out.println("数学成绩:" + s.getMath());
    }

    public void printAverageScore() {
        System.out.println("平均成绩:" + (s.getChinese() + s.getMath())/2.0);
    }
}

Test1.java

public class Test1 {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 18, 66, 88);
        StudentOperator so = new StudentOperator(s1);
        so.printScore();
    }
}

CodeBlock

CodeDemo1.java

import java.util.Arrays;
public class CodeDemo1 {
    public static String schoolName;
    public static String[] cards = new String[10];
    //静态代码块:
    //格式:static{}
    //特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次//作用:完成类的初始化,例如:对静态变量的初始化赋值。
    static{
        System.out.println("静态代码块执行了");
        schoolName = "黑马程序员";
        cards[0] = "A";
        cards[1] = "2";
        cards[2] = "3";
    }
    public static void main(String[] args) {
        System.out.println("main方法执行了");
        System.out.println(schoolName);
        System.out.println(Arrays.toString(cards));
    }
}

结果

静态代码块执行了
main方法执行了
黑马程序员
[A, 2, 3, null, null, null, null, null, null, null]

CodeDemo2.java

package com_itheima._02CodeBlock;
public class CodeDemo2 {
    //实例代码块:无static修饰。属于对象,每次创建对象时,都会优先执行一次//作用:初始化对象的实例资源。
    {
        System.out.println("---------实例代码块---------");
    }

    public static void main(String[] args) {
        System.out.println("---------main方法执行---------");
        new CodeDemo2();
        new CodeDemo2();
        new CodeDemo2();
    }
}

结果

---------main方法执行---------
---------实例代码块---------
---------实例代码块---------
---------实例代码块---------

StaticMethod

public class Student {
    public static int count = 0;
    private String name;
    private int age;
    private double chinese;
    private double math;

    public Student() {
        count++;
    }
    public Student(String name, int age, double chinese, double math) {
        this.name = name;
        this.age = age;
        this.chinese = chinese;
        this.math = math;
        count++;
    }

    //静态方法中可以访问静态成员变量和静态方法,不能访问非静态成员变量和成员方法
    public static int getCount() {
        return count;
    }

    //静态方法中不可以出现this关键字
    public static void setCount(int count) {
        Student.count = count;
    }

    //实例方法既可以直接访问静态成员变量和静态方法,也可以访问非静态成员变量和成员方法
    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 double getChinese() {
        return chinese;
    }
    public void setChinese(double chinese) {
        this.chinese = chinese;
    }
    public double getMath() {
        return math;
    }
    public void setMath(double math) {
        this.math = math;
    }
}

 ExtendsDemo

子类可以继承父类非私有成员

Extends4Feature 父类、子类与子类方法内相同名字变量的访问


public class Test2 {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();
    }
}

class Fu{
    String name = "Fu's name";
}

class Zi extends Fu{
    String name = "Zi's name";

    public void show(){
        String name = "show's name";
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);//父类变量
    }
}

结果

show's name
Zi's name
Fu's name

Extends5Override 重写父类方法

子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)
重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
私有方法、静态方法不能被重写,如果重写会报错。
重写的规范:声明不变,重新实现
@Override //方法重写的校验注解:要求方法名称和形参列表与被重写方法一致,否则编译不通过
package com.itheima.extends5Override;

public class Test2 {
    public static void main(String[] args) {
        Student s = new Student("张三", 18, 66, 88);
       System.out.println(s);
    }
}

class Student{
    private String name;
    private int age;
    private double chinese;
    private double math;

    public Student(){}

    public Student(String name, int age, double chinese, double math) {
        this.name = name;
        this.age = age;
        this.chinese = chinese;
        this.math = math;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", chinese=" + chinese +
                ", math=" + math +
                '}';
    }

    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 double getChinese() { return chinese; }
    public void setChinese(double chinese) { this.chinese = chinese; }
    public double getMath() { return math; }
    public void setMath(double math) { this.math = math; }
}

结果

Student{name='张三', age=18, chinese=66.0, math=88.0}

Extends6Constructor 构造器

默认情况下,子类全部构造器的第一行代码都是 super()(写不写都有),它会调用父类的无参数构造器。
如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(.),指定去调用父类的有参数构造器,否则会报错。
Test2.java
public class Test2 {
    public static void main(String[] args) {
        Teacher t = new Teacher("张三",'男',"Java");
        System.out.println(t);
    }
}

class People{
    private String name;
    private char sex;

    public People(){
        System.out.println("People()");
    }
    public People(String name,char sex){
        System.out.println("People(String,char)");
        this.name = name;
        this.sex = sex;
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public char getSex() { return sex; }
    public void setSex(char sex) { this.sex = sex; }
}

class Teacher extends People{
    private String skill;
    public Teacher(){ System.out.println("Teacher()"); }
    public Teacher(String name,char sex,String skill){
        super(name,sex);//调用父类的构造方法
        this.skill = skill;
        System.out.println("Teacher(String,char,String)");
    }

    public String getSkill() { return skill; }
    public void setSkill(String skill) { this.skill = skill; }

    public String toString(){
        return "Teacher{" +
                "name=" + getName() +
                ", sex=" + getSex() +
                ", skill=" + skill +
                "}";
    }
}

结果

People(String,char)
Teacher(String,char,String)
Teacher{name=张三, sex=男, skill=Java}

Test3.java

注意:this(...)调用兄弟构造器或super(...)调用父类构造器,必须放在第一行,而且二者不能同时出现。因为this构造器已经调用了super构造器了

//理解this(...)调用兄弟构造器
public class Test3 {
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student("李四", '男', 19);
        System.out.println(s1);
        System.out.println(s2);
    }
}

class Student{
    private String name;
    private char sex;
    private int age;
    private String schoolName;

    public Student() {
        //注意:this(...)调用兄弟构造器或super(...)调用父类构造器,必须放在第一行,而且二者不能同时出现。因为this构造器已经调用了super构造器了
        this("张三", '男', 18, "清华大学");
    }

    public Student(String name, char sex, int age) {
        this(name, sex, age, "北京大学");
    }

    public Student(String name, char sex, int age, String schoolName) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.schoolName = schoolName;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", age=" + age +
                ", schoolName='" + schoolName + '\'' +
                '}';
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public char getSex() { return sex; }
    public void setSex(char sex) { this.sex = sex; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getSchoolName() { return schoolName; }
    public void setSchoolName(String schoolName) { this.schoolName = schoolName; }
}
结果
Student{name='张三', sex=男, age=18, schoolName='清华大学'}
Student{name='李四', sex=男, age=19, schoolName='北京大学'}

 FinalDemo

使用了 static final 修饰的成员变量就被称为常量
作用:常用于记录系统的配置信息。
使用常量记录系统配置信息的优势、执行原理
代码可读性更好,可维护性也更好,
程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
Constant.java
public class Constant {
    public static final double PI = 3.14;
    public static final double E = 2.71828;
    public static final double G = 9.8;
    public static final double C = 299792458;
    public static final String SYSTEM_NAME = "Windows";
}
1.final修饰局部变量:有且仅能被赋值一次
2.final修饰基本类型的变量,变量存储的数据不能被改变。
3.final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的

finalDemo1.java


public class finalDemo1 {
    final int a = 10;

    //arr = new int[]{4,5,6};报错
    public static void main(String[] args) {
        final int[] arr = {1,2,3,4,5,6};
        arr[1] = 9;
    }

    public void test1(){
        final int a = 10;
        //a = 20;
    }
}

//final修饰的类不能被继承
final class A{}

//final修饰的方法不能被重写
class C{
    public final void show() { System.out.println("show"); }
}

Enum

枚举都是最终类,不可以被继承,枚举类都是继承java.lang.Enum类的。
枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量会记住枚举类的一个对象。
枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
枚举类的第一行:只能罗列枚举对象的名称,这些名称本质是常量
Test.java
public enum A {
    //枚举类的第一行:只能罗列枚举对象的名称,这些名称本质是常量
    X,Y,Z;
}
public class Test {
    public static void main(String[] args) {
        A a1 = A.X;
        System.out.println(a1);//X

        A a2 = A.Y;
        System.out.println(a2);//Y

        System.out.println(a1.name());// X
        System.out.println(a2.name());// Y
        System.out.println(a1.ordinal());//0
        System.out.println(a2.ordinal());//1
    }
}

Test2.java

public class Test2 {
    public static void main(String[] args) {
        //掌握枚举类的应用场景:做信息的分类和标志
        //模拟上下左右移动
        //第一种是常量做信息标志和分类,但参数值不受约束
        move(Constant.LEFT);
        move2(Direction.UP);
    }

    public static void move2(Direction direction){
        switch (direction){
            case UP:
                System.out.println("向上");break;
            case DOWN:
                System.out.println("向下");break;
            case LEFT:
                System.out.println("向左");break;
            case RIGHT:
                System.out.println("向右");break;
            default:
                System.out.println("输入有误");
        }
   }

    public static void move(int direction){
        switch (direction){
            case 0:
                System.out.println("向上");break;
            case 1:
                System.out.println("向下"); break;
            case 2:
                System.out.println("向左");break;
            case 3:
                System.out.println("向右");break;
            default:
                System.out.println("输入有误");
        }
    }
}

结果

向左
向上

Polymorphsm 多态

多态的前提:有继承/实现关系;存在父类引用子类对象;存在方法重写
使用多态的好处:1.在多态形式下,右边对象是解耦合的,更便于扩展和维护 2.定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
多态的弊端:在Java多态场景中,当通过父类引用操作子类对象时,无法直接访问子类独有的属性和方法,需要通过向下转型才能调用
if(a instanceof Dog)可判断对象a是否属于Dog类

public class Test1 {
    //多态的前提:有继承/实现关系;存在父类引用子类对象;存在方法重写
    //使用多态的好处:1.在多态形式下,右边对象是解耦合的,更便于扩展和维护  2.定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
    //多态的弊端:在Java多态场景中,当通过父类引用操作子类对象时,无法直接访问子类独有的属性和方法,需要通过向下转型才能调用。
    //if(a instanceof Dog)可判断对象a是否属于Dog类
    public static void main(String[] args) {
        Animal a1 = new Dog();
        Animal a2 = new Cat();
        System.out.println(a1.name);//成员变量:编译看左边,运行看左边 //Animal
        System.out.println(a2.name);//Animal
        a1.eat();//方法:编译看左边,运行看右边 //Dog eat
        a2.eat();//Cat eat
        go(a1);
        go(a2);
        System.out.println("======================");
        //强制类型转换的一个注意事项
        //存在继承/实现关系就可以在编译阶段进行强制类型转换,编译阶段不会报错,
        //运行时,如果发现对象的真实类型与强转后的类型不同,就会报类型转换异常(ClassCastException)的错误出来。
        // 比如Dog d2 = (Dog) a2;  a2是Cat类型,不能强转为Dog类型
        //java 建议强制转换前,应该判断对象的真实类型是否与强转后的类型一致,不一致就报错。
        Dog d = (Dog) a1;
        d.run();

        if(a1 instanceof Dog){
            Dog d2 = (Dog) a1;
            d2.run();
        }
    }

    public static void go(Animal a){
        System.out.println("运行go函数");
        a.eat();
        //并不知道a1是Dog类型,所以不能直接调用Dog特有方法run
        if(a instanceof Dog){
            Dog d2 = (Dog) a;
            d2.run();
        }
    }
}

class Animal {
    String name = "Animal";
    public void eat() { System.out.println("Animal eat"); }
}

class Dog extends Animal {
    String name = "Dog";
    public void eat() { System.out.println("Dog eat"); }
    public void run() { System.out.println("Dog run"); }
}

class Cat extends Animal {
    String name = "Cat";
    public void eat() { System.out.println("Cat eat"); }
}

结果

Animal
Animal
Dog eat
Cat eat
运行go函数
Dog eat
Dog run
运行go函数
Cat eat
======================
Dog run
Dog run

PolymorphsmDemo 多态

lombok技术可以实现为类自动添加getter/setter/toString/equals/hashCode等方法

Card.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//lombok技术可以实现为类自动添加getter/setter/toString/equals/hashCode等方法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Card {
    private String carId;
    private String name;
    private String phone;
    private double money;

    public void deposit(double money){ this.money += money; }
    public void consume(double money){ this.money -= money; }
}

SilverCard.java

public class SilverCard extends Card{
    public SilverCard(String carId, String name, String phone, double money) { super(carId, name, phone, money); }
    @Override
    public void consume(double money) {
        System.out.println("您当前消费" + money);
        System.out.println("优惠后的消费为" + money * 0.9);
        if(getMoney() < money * 0.9){
            System.out.println("您的余额不足,请充值");return;
        }
        setMoney(getMoney() - money * 0.9);
    }
}

GoldCard.java

public class GoldCard extends Card{
    public GoldCard(String carId, String name, String phone, double money) { super(carId, name, phone, money); }

    @Override
    public void consume(double money) {
        System.out.println("您当前消费" + money);
        System.out.println("优惠后的消费为" + money * 0.8);
        if(getMoney() < money * 0.8){
            System.out.println("您的余额不足,请充值");return;
        }
        setMoney(getMoney() - money * 0.8);
        if(money * 0.8 >= 200){
            printTicket();
        }
        else {
            System.out.println("当前消费未满200,您没有优惠券");
        }
    }

    public void printTicket(){ System.out.println("您的优惠券"); }
}

Test.java

import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
        //目标:加油站支付小程序
        //1.创建卡片父类,以便创建金卡、银卡对象,封装车主信息
        //2.定义卡片父类,里面是金卡和银卡共同的属性和方法
        //3.定义金卡类,继承卡片父类,必须重写消费方法,独有功能洗车票
        //4.定义银卡类,继承卡片父类,必须重写消费方法
        GoldCard gc = new GoldCard("123456789", "张三", "15123456789", 1000);
        SilverCard sc2 = new SilverCard("987654321", "李四", "15123456789", 1000);
        pay(gc);
    }

    //支付机:用一个方法来刷卡。可能接收金卡或银卡。根据不同的卡类型,调用不同的消费方法。
    public static void pay(Card c) {
        System.out.println("请您输入当前消费的金额");
        Scanner sc = new Scanner(System.in);
        double money = sc.nextDouble();
        c.consume(money);
    }
}

 Abstract Class 抽象类

抽象类中不一定要有抽象方法,有抽象方法的类必须是抽象类
类有的成员:成员变量、方法、构造器,抽象类都可以有,
抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类
父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现。
我们设计这样的抽象类,就是为了更好的支持多态。

A.java

public abstract class A {
    private String name;
    private int age;

    public A() { System.out.println("抽象类A的无参构造器"); }

    public A(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("抽象类A的有参构造器");
    }

    public abstract void show();

    public void show2(){ System.out.println("抽象类A的show2方法"); }

    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; }
}

B.java

public class B extends A{
    @Override
    public void show() { System.out.println("B类重写show方法"); }
}

AbstractDemo1.java

public class AbstractDemo1 {
    public static void main(String[] args) {
        B b = new B();
        b.setName("zhang san");
        b.setAge(20);
        b.show();
        b.show2();
    }
}

res

抽象类A的无参构造器
B类重写show方法
抽象类A的show2方法

模板方法设计模式

people.java

//模板方法设计模式
public abstract class People {
    //模板方法是给子类直接使用的,不能被子类重写。
    //一旦子类重写了模板方法,模板方法就失效了。
    public final void write(){
        System.out.println("公共部分1");
        writeMain();
        System.out.println("公共部分2");
    }

    public abstract void writeMain();
}

Student.java

public class Student extends People{
    @Override
    public void writeMain(){ System.out.println("Student writeMain");}
}

Teacher.java

public class Teacher extends People{
    @Override
    public void writeMain(){ System.out.println("Teacher writeMain"); }
}

Test.java

public class Test {
    public static void main(String[] args) {
        Student s = new Student();
        s.write();//调用父类的write方法
        Teacher t = new Teacher();
        t.write();//调用父类的write方法
    }
}

Interface 接口

JDK 8之前,接口中只能定义常量和抽象方法。
注意:接口不能创建对象。
接口是用来被类实现(implements)的,实现接口的类称为实现类,,一个类可以同时实现多个接口,
1、常量:接口中定义常量可以省略public static final不写,默认会加上去。
2、抽象方法:接口中定义抽象方法的时候可以省略public abstract不写,默认会加上去。

实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则这个类必须定义成抽象类
A.java
package com.itheima.interface1;

public interface A {
    // 1、常量:接口中定义常量可以省略public static final不写,默认会加上去。
    //public static final String SCHOOL_NAME = "黑马程序员";
    String SCHOOL_NAME = "黑马程序员";

    // 2、抽象方法:接口中定义抽象方法的时候可以省略public abstract不写,默认会加上去。
    public abstract void run();

    void go();
}

B.java

public interface B {
    void play();
}

Test.java

public class Test {
    public static void main(String[] args) {
        System.out.println(A.SCHOOL_NAME);
        C c = new C();
        c.run();
        c.go();
        c.play();
    }
}

//实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则这个类必须定义成抽象类
class C implements A,B{
    @Override
    public void run() { System.out.println("C类重写接口A中的run方法"); }
    @Override
    public void go() { System.out.println("C类重写接口A中的go方法"); }
    @Override
    public void play() { System.out.println("C类重写接口B中的play方法"); }
}

res

黑马程序员
C类重写接口A中的run方法
C类重写接口A中的go方法
C类重写接口B中的play方法

Interface2

//弥补了类单继承的不足,一个类同时可以实现多个接口,使类的角色更多,功能更强大。
//让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现(更利于程序的解耦合
public class Test {
    public static void main(String[] args) {
        People p = new Student();
        Driver d = new Student();d.drive();
        BoyFriend bf = new Student();bf.go();
    }
}

class Student extends People implements Driver, BoyFriend {
    public void drive() { System.out.println("student drive"); }

    public void go() { System.out.println("student go"); }
}

interface Driver {
    void drive();
}

interface BoyFriend {
    void go();
}

class People{}

res

student drive
student go

Interface3Demo

ClassDataInter.java

public interface ClassDataInter {
    void printAllStudentInfos();
    void printAverageScore();
}

ClassDataInterImpl1.java

// 定义第一套实现类,实现接口:实现打印学生信息,实现打印平均分。
public class ClassDataInterImpl1 implements ClassDataInter{
    private Student[] students;
    public ClassDataInterImpl1(Student[] students) { this.students = students; }
    @Override
    public void printAllStudentInfos() {
        System.out.println("全班信息如下:");
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i].getName() + " " + students[i].getSex() + " " + students[i].getScore());
        }
    }

    @Override
    public void printAverageScore() {
        double sum = 0;
        for (int i = 0; i < students.length; i++) {
            sum += students[i].getScore();
        }
        System.out.println("平均成绩为:" + sum / students.length);
    }
}

ClassDataInterImpl2.java

// 定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分)
public class ClassDataInterImpl2 implements ClassDataInter{
    private Student[] students;
    public ClassDataInterImpl2(Student[] students) { this.students = students; }
    @Override
    public void printAllStudentInfos() {
        int maleCount = 0;
        for (int i = 0; i < students.length; i++) {
            Student s = students[i];
            System.out.println(s.getName() + " " + s.getSex() + " " + s.getScore());
            if(s.getSex() == '男'){ maleCount++; }
        }
        System.out.println("男学生人数:" + maleCount);
        System.out.println("女学生人数:" + (students.length - maleCount));
    }

    @Override
    public void printAverageScore() {
        double sum = students[0].getScore();
        double max = students[0].getScore();
        double min = students[0].getScore();
        for (int i = 1; i < students.length; i++) {
            sum += students[i].getScore();
            max = Math.max(max, students[i].getScore());
            min = Math.min(min, students[i].getScore());
        }
        System.out.println("平均成绩为:" + (sum - max - min) / (students.length - 2));
        System.out.println("最高分:" + max);
        System.out.println("最低分:" + min);
    }
}

Test.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

public class Test {
    public static void main(String[] args) {
        Student[] allStudents = new Student[10];
        allStudents[0] = new Student("张三", '男', 100);
        allStudents[1] = new Student("李四", '女', 99);
        allStudents[2] = new Student("王五", '男', 98);
        allStudents[3] = new Student("赵六", '女', 97);
        allStudents[4] = new Student("钱七", '男', 96);
        allStudents[5] = new Student("孙八", '女', 95);
        allStudents[6] = new Student("周九", '男', 94);
        allStudents[7] = new Student("吴十", '女', 93);
        allStudents[8] = new Student("郑十一", '男', 92);
        allStudents[9] = new Student("冯十二", '女', 91);

        //提供两套业务实现方案,支持灵活切换(解耦合)
        //定义一个接口(规范思想):必须完成打印全班学生信息,打印平均分。
        // 定义第一套实现类,实现接口:实现打印学生信息,实现打印平均分。
        // 定义第二套实现类,实现接口:实现打印学生信息(男女人数),实现打印平均分(去掉最高分和最低分)
        ClassDataInter cdi1 = new ClassDataInterImpl1(allStudents);
        cdi1.printAllStudentInfos();
        cdi1.printAverageScore();
        System.out.println("------------------------");
        ClassDataInter cdi2 = new ClassDataInterImpl2(allStudents);
        cdi2.printAllStudentInfos();
        cdi2.printAverageScore();

    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Student {
    private String name;
    private char sex;
    private double score;
}

res

全班信息如下:
张三 男 100.0
李四 女 99.0
王五 男 98.0
赵六 女 97.0
钱七 男 96.0
孙八 女 95.0
周九 男 94.0
吴十 女 93.0
郑十一 男 92.0
冯十二 女 91.0
平均成绩为:95.5
------------------------
张三 男 100.0
李四 女 99.0
王五 男 98.0
赵六 女 97.0
钱七 男 96.0
孙八 女 95.0
周九 男 94.0
吴十 女 93.0
郑十一 男 92.0
冯十二 女 91.0
男学生人数:5
女学生人数:5
平均成绩为:95.5
最高分:100.0
最低分:91.0

Interface4 jdk新特性

A.java

//jdk8之后新特性
public interface A {
    // 1、默认方法(普通实例方法):必须加default修饰,
    // 默认会用public修饰。如何调用?使用接口的实现类的对象来调用。
    default void go(){
        System.out.println("interface A:default void go()");
        run();
    }

    //2、私有方法(JDK 9开始才支持的)// 私有的实例方法。
    //如何调用?使用接口中的其他实例方法来调用
    private void run(){ System.out.println("interface A:private void run()"); }

    // 3、静态方法
    // 默认会用public修饰。如何调用?只能使用当前接口名来调用
    public static void show(){ System.out.println("interface A:public static void show()"); }
}

Test.java

public class Test {
    public static void main(String[] args) {
        AImpl a = new AImpl();
        a.go();
        A.show();
    }
}

class AImpl implements A { }

res

interface A:default void go()
interface A:private void run()
interface A:public static void show()

 interface5 

1、接口与接口可以多继承:一个接口可以同时继承多个接口[重点]。

2、类与类:单继承 一个类只能继承一个直接父类。

3、类与接口:多实现,一个类可以同时实现多个接口。

4、接口与接口: 多继承,一个接口可以同时继承多个接口。

5、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。[了解]

6、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的方法,实现类会优先用父类的。

7、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

public class Test {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.show();
        d.go();
    }
}

// 1、接口与接口可以多继承:一个接口可以同时继承多个接口[重点]。
// 类与类:单继承 一个类只能继承一个直接父类
// 类与接口:多实现,一个类可以同时实现多个接口。
// 接口与接口: 多继承,一个接口可以同时继承多个接口。
interface A {
    void show1();
}
interface B {
    void show2();
}
interface C extends A, B {
    void show3();
}
class D implements C {
    public void show1() { System.out.println("show1"); }
    public void show2() { System.out.println("show2"); }
    public void show3() { System.out.println("show3"); }
}

//2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。[了解]
interface A1 {
    void show();
}
interface B1 {
    String show();
}
/*
class C1 implements A1, B1 {
    //报错
    public void show() {
        System.out.println("show");
    }
    public String show() {
        return "show";
    }
}*/

//3.一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的方法,实现类会优先用父类的。
interface A2 {
    default void show() { System.out.println("interface A2:default void show()"); }
}

class Animal{
    public void show() { System.out.println("Animal:public void show()"); }
}

class Dog extends Animal implements A2 {
    public void go(){
        show();//Animal:public void show()
        super.show();//Animal:public void show()
        A2.super.show();//interface A2:default void show()
    }
}

//4. 一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。

res

Animal:public void show()
Animal:public void show()
Animal:public void show()
interface A2:default void show()

InterfaceDemo 家电控制模拟

Switch.java

public interface Switch {
    void press();
}

JD.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class JD implements Switch{
    private String name;
    private boolean status;//默认值为false

    @Override
    public void press() {
        //控制当前设备开关
        status = !status;
    }
}

TV.java

public class TV extends JD{
    public TV(String name, boolean status) { super(name, status); }
}

WashMachine.java

public class WashMachine extends JD{
    public WashMachine(String name, boolean status) { super(name, status); }
}

Lamp.java

public class Lamp extends JD{
    public Lamp(String name, boolean status) { super(name, status); }
}

Air.java

public class Air extends JD{
    public Air(String name, boolean status) { super(name, status); }
}

SmartControl.java

public class SmartControl {
    private static final SmartControl sm = new SmartControl();
    private SmartControl() {}
    public static SmartControl getInstance() { return sm; }
    public static void printAllstatus(JD[] jds) {
        for (int i = 0; i < jds.length; i++) {
            System.out.println((i+1) + " " + jds[i].getName() + "目前状态:" + (jds[i].isStatus() ? "开" : "关"));
        }
    }

    public void control(JD jd){
        System.out.println(jd.getName() + "目前状态:" + (jd.isStatus() ? "开" : "关"));
        System.out.println("开始您的操作");
        jd.press();
        System.out.println(jd.getName() + "状态变成:" + (jd.isStatus() ? "开" : "关"));
    }
}

Test.java

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        // 目标:面向对象编程实现智能家居控制系统。
        // 角色:设备(吊灯,电视机,洗衣机,落地窗,....)/1具备的功能:开和关。
        //谁控制他们:智能控制系统(单例对象),控制调用设备的开和关。
        //1、定义设备类:创建设备对象代表家里的设备。
        //2、准备这些设备对象,放到数组中,代表整个家庭的设备。
        JD[] jds = new JD[4];
        jds[0] = new TV("电视", false);
        jds[1] = new WashMachine("洗衣机", false);
        jds[2] = new Lamp("吊灯", false);
        jds[3] = new Air("空调", false);

        //3、为每个设备制定一个开个关的功能。定义一个接口,让JD实现开关功能。
        //4、创建智能控制系统对象,控制设备开和关。
        //5、控制电视
        SmartControl smartControl = SmartControl.getInstance();
        //smartControl.control(jds[0]);

        //6 、提示用户操作,a、展示全部设备的当前情况。b、让用户选择哪一个操作// 打印全部设备的开和关的现状。
        while(true){
            SmartControl.printAllstatus(jds);
            System.out.println("请选择您要操作的设备序号,输入q退出");
            Scanner sc = new Scanner(System.in);
            String command = sc.next();
            switch (command){
                case "1":
                    smartControl.control(jds[0]);break;
                case "2":
                    smartControl.control(jds[1]);break;
                case "3":
                    smartControl.control(jds[2]);break;
                case "4":
                    smartControl.control(jds[3]);break;
                case "q":
                    System.out.println("感谢使用智能控制系统,欢迎下次使用");return;
                default:
                    System.out.println("您输入的序号有误,请重新输入");
            }
        }
    }
}
抽象类与接口的区别
相同点:
1、多是抽象形式,都可以有抽象方法,都不能创建对象
2、都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现。
3、一个类继承抽象类,或者实现接口,都必须重写完他们的抽象方法,否则自己要成为抽象类或者报错!
4、都能支持的多态,都能够实现解耦合。
不同点:
1、抽象类中可以定义类的全部普通成员接口只能定义常量,抽象方法(JDK8新增的三种方式)
2、抽象类只能被类单继承,接口可以被类多实现。
3、一个类继承抽象类就不能再继承其他类,一个类实现了接口(还可以继承其他类或者实现其他接口)。
4、抽象类体现模板思想:更利于做父类,实现代码的复用性。最佳实践
5、接口更适合做功能的解耦合:解耦合性更强更灵活。最佳实践

SingleInstance 单例设计模式

A.java

//饿汉式单例设计模式
public class A {
    //2.定义一个静态变量,用于基本本类的唯一实例
    private static A a = new A();

     //1. 私有化构造方法
    private A(){}

    public static A getInstance(){ return a; }
}

B.java

//懒汉式单例设计模式:要用类的对象时,才创建对象,第一次用到时创建,以后都用同一个对象。
public class B {
    private static B instance;

    private B() { }

    public static B getInstance() {
        if (instance == null) {
            instance = new B();
        }
        return instance;
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        //目标:设计单例类
        //A a1 = new A(); //错误,不能new对象
        A a1 = A.getInstance();
        A a2 = A.getInstance();
        System.out.println(a1 == a2);//true
    }
}

InnerClass 内部类

Outer.java

public class Outer {
    public static String schoolName = "黑马程序员";
    private int age;

    public Outer() { System.out.println("Outer()"); }
    public void run(){ System.out.println("Outer.run()"); }
    //成员内部类:无static修饰,属于外部类的对象持有的
    public class Inner {
        private String name;
        public Inner() { System.out.println("Inner()"); }

        public Inner(String name) {
            System.out.println("Inner(String name)");
            this.name = name;
        }

        public void show() {
            System.out.println("Inner show");
            //成员内部类中可以直接访问外部类的静态成员
            System.out.println("Outer:public static String schoolName:" + Outer.this.schoolName);
            System.out.println("Outer:private int age:" + Outer.this.age);
            Outer.this.run();//访问外部类的成员方法
        }

        public String getName() { return name; }

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

InnerClassDemo1.java

public class InnerClassDemo1 {
    public static void main(String[] args) {
        Outer.Inner oi = new Outer().new Inner();
        oi.setName("张三");
        oi.show();
        //成员内部类中可以直接访问外部类的静态成员,也可以直接访问外部类的实例成员
    }
}

InnerClass2

Outer.java

public class Outer {
    public static String schoolName = "黑马程序员";
    private String name;
    public static class Inner {
        public void show() {
            System.out.println("public static class Inner.show");
            System.out.println("Outer.schoolName:" + Outer.schoolName);//静态内部类中可以直接访问外部类的静态成员
            //System.out.println("Outer.name:" + Outer.this.name);//静态内部类中不可以直接访问外部类的实例成员
        }
    }

    public static String getSchoolName() { return schoolName; }
    public static void setSchoolName(String schoolName) { Outer.schoolName = schoolName; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

InnerClassDemo2.java

public class InnerClassDemo2 {
    public static void main(String[] args) {
        //目标:搞清楚静态内部类的语法
        // 创建对象:外部类名.内部类名对象名=new 外部类名.内部类名();
        //静态内部类中是否可以直接访问外部类的静态成员?可以!
        //静态内部类中是否可以直接访问外部类的实例成员?不可以!
        Outer.Inner oi = new Outer.Inner();
    }
}

InnerClass  AnonymousClass

Test.java

public class Test {
    public static void main(String[] args) {
        //认识匿名内部类
        //匿名内部类本质是一个子类,同时会立即构建一个子类对象
        Animal a = new Animal() {
            @Override
            public void cry() {
                System.out.println("cat cry");
            }
        };
        a.cry();
    }
}

abstract class Animal {
    public abstract void cry();
}

res

cat cry

Test2.java

public class Test2 {
    public static void main(String[] args) {
        //目标:搞清楚匿名内部类的使用形式(语法): 通常可以做为一个对象参数传输给方法使用。
        //需求:学生,老师都要参加游泳比赛。
        Swim s1 = new Swim() {
            @Override
            public void swimming() { System.out.println("匿名内部类实现Swim接口,创建对象s1"); }
        };
        start(s1);
        System.out.println("--------------------");
        start(new Swim() {
            @Override
            public void swimming() { System.out.println("匿名内部类实现Swim接口,创建对象s2"); }
        });
    }

    public static void start(Swim s){
        System.out.println("开始。。");
        s.swimming();
        System.out.println("结束。。");
    }
}

interface Swim {
    void swimming();
}

res

开始。。
匿名内部类实现Swim接口,创建对象s1
结束。。
--------------------
开始。。
匿名内部类实现Swim接口,创建对象s2
结束。。

Test3.java

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Test3 {
    public static void main(String[] args) {
        // 目标:搞清楚几个名内部类的使用场景。
        // 需求:创建一个登录窗口,窗口上只有一个登录按钮
        JFrame win = new JFrame("登录窗口");
        win.setSize(300,200);
        win.setLocationRelativeTo(null);//居中显示。
        win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        win.add(panel); // 添加面板

        JButton btn = new JButton("登录");
        panel.add(btn);

        //java要求必须给这个按钮添加一个点击事件监听器对象,这样就可以监听用户的点击操作,就可以做出反应。
        //开发中不是我们要主动去写匿名内部类,而是用别人的功能的时候,别人可以让我们写一个匿名内部类吗,我们才会写!
        /*
        ClickListener cl = new ClickListener();
        btn.addActionListener(cl);*/

        //更简便的写法是使用匿名内部类,匿名内部类对象是在创建的时候,就直接调用了addActionListener方法,把匿名内部类对象传递给addActionListener方法。
        btn.addActionListener(new ActionListener() {
            private int count = 0;

            @Override
            public void actionPerformed(ActionEvent e) { System.out.println("用户第" + ++count + "次点击登陆按钮"); }
        });

        win.setVisible(true);
    }
}

class ClickListener implements ActionListener {
    private static int count = 0;

    @Override
    public void actionPerformed(ActionEvent e) { System.out.println("用户第" + ++count + "次点击登陆按钮"); }
}

res

用户第1次点击登陆按钮
用户第2次点击登陆按钮
用户第3次点击登陆按钮
用户第4次点击登陆按钮

Test4.java   Arrays.sort

import java.util.Arrays;
import java.util.Comparator;

public class Test4 {
    public static void main(String[] args) {
        Student[] students = new Student[6];
        students[0] = new Student("张三", 35, 170, '男');
        students[1] = new Student("李四", 28, 168, '男');
        students[2] = new Student("王五", 25, 165, '女');
        students[3] = new Student("赵六", 19, 172, '男');
        students[4] = new Student("孙七", 27, 170, '女');
        students[5] = new Student("钱八", 36, 168, '女');

        //需求:按钮年龄升序排序。可以调用sun公司写好的API直接对数组进行排序。
        // public static void sort(T[]a,Comparator<T> c)
        //             参数一:需要排序的数组
        //             参数二:需要给sort声明一个Comparator比较器对象(指定排序的规则)
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                //指定排序规则:
                //如果你认为左边对象要放后面,那么返回正整数//如果你认为左边对象要放前面,那么返回负整数//如果两边相等那么返回0。
                return o1.getAge() - o2.getAge();
            }
        });
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Student{
    private String name;
    private int age;
    private double height;
    private char sex;
}

res

Student(name=赵六, age=19, height=172.0, sex=男)
Student(name=王五, age=25, height=165.0, sex=女)
Student(name=孙七, age=27, height=170.0, sex=女)
Student(name=李四, age=28, height=168.0, sex=男)
Student(name=张三, age=35, height=170.0, sex=男)
Student(name=钱八, age=36, height=168.0, sex=女)

Lambda

Lambda表达式:JDK8 开始新增的一种语法形式,它表示函数。
可以用于替代某些匿名内部类对象,从而让程序更简洁,可读性更好
(被重写方法的形参列表)->{被重写方法的方法体代码}
Lambda并不是可以简化全部的匿名内部类,Lambda只能简化函数式接口的匿名内部类
函数式接口:只有一个抽象方法的接口。声明函数式接口的注解:@FunctionalInterface
LambdaDemo1.java
public class LambdaDemo1 {
    public static void main(String[] args) {
        Animal a = new Animal() {
            @Override
            public void cry() {
                System.out.println("叫了一声");
            }
        };
        a.cry();


        //错误示范:Lambda并不是可以简化全部的匿名内部类,Lambda只能简化函数式接口的匿名内部类。
        /*Animal a1 = () -> {
            @Override
            public void cry() {
                System.out.println("叫了一声");
            }
        };*/
        Swim s1 = () -> {
            System.out.println("s1调用swimming方法");
        };
        s1.swimming();

    }
}

//函数式接口:只有一个抽象方法的接口。
@FunctionalInterface  //声明函数式接口的注解
interface Swim{
    void swimming();
}

abstract class Animal {
    public abstract void cry();
}

res

叫了一声
s1调用swimming方法

LambdaDemo2.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Comparator;

public class LambdaDemo2 {
    public static void main(String[] args) {
        test1();
        test2();
    }

    public static void test1(){
        Student[] students = new Student[6];
        students[0] = new Student("张三", 35, 170, '男');
        students[1] = new Student("李四", 28, 168, '男');
        students[2] = new Student("王五", 25, 165, '女');
        students[3] = new Student("赵六", 19, 172, '男');
        students[4] = new Student("孙七", 27, 170, '女');
        students[5] = new Student("钱八", 36, 168, '女');

        //需求:按钮年龄升序排序。可以调用sun公司写好的API直接对数组进行排序。
        // public static void sort(T[]a,Comparator<T> c)
        //             参数一:需要排序的数组
        //             参数二:需要给sort声明一个Comparator比较器对象(指定排序的规则)
        /*Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                //指定排序规则:
                //如果你认为左边对象要放后面,那么返回正整数。
                //如果你认为左边对象要放前面,那么返回负整数。
                //如果两边相等那么返回0。
                return o1.getAge() - o2.getAge();
            }
        });*/

        /*Arrays.sort(students, (o1, o2) -> {
            return o1.getAge() - o2.getAge();
        });*/

        Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());

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

    public static void test2(){
        // 目标:搞清楚几个名内部类的使用场景。
        // 需求:创建一个登录窗口,窗口上只有一个登录按钮
        JFrame win = new JFrame("登录窗口");
        win.setSize(300,200);
        win.setLocationRelativeTo(null);//居中显示。
        win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        win.add(panel); // 添加面板

        JButton btn = new JButton("登录");
        panel.add(btn);

        //java要求必须给这个按钮添加一个点击事件监听器对象,这样就可以监听用户的点击操作,就可以做出反应。
        //开发中不是我们要主动去写匿名内部类,而是用别人的功能的时候,别人可以让我们写一个匿名内部类吗,我们才会写!
        /*btn.addActionListener((ActionEvent e) -> {
                System.out.println("点击登陆按钮");
        });*/

        /*btn.addActionListener((e) -> {
            System.out.println("点击登陆按钮");
        });*/

        btn.addActionListener(e -> System.out.println("点击登陆按钮"));
        win.setVisible(true);
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Student{
    private String name;
    private int age;
    private double height;
    private char sex;
}

res

Student(name=赵六, age=19, height=172.0, sex=男)
Student(name=王五, age=25, height=165.0, sex=女)
Student(name=孙七, age=27, height=170.0, sex=女)
Student(name=李四, age=28, height=168.0, sex=男)
Student(name=张三, age=35, height=170.0, sex=男)
Student(name=钱八, age=36, height=168.0, sex=女)
点击登陆按钮
点击登陆按钮

Method1Reference   LambdaSort

Demo2.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;

public class Demo2 {
    public static void main(String[] args) {
        Student2[] students = new Student2[6];
        students[0] = new Student2("张三", 35, 170, '男');
        students[1] = new Student2("李四", 28, 168, '男');
        students[2] = new Student2("王五", 25, 165, '女');
        students[3] = new Student2("赵六", 19, 172, '男');
        students[4] = new Student2("孙七", 27, 170, '女');
        students[5] = new Student2("钱八", 36, 168, '女');
        
        //Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());
        //Arrays.sort(students, (o1, o2) -> Student.compareByAge(o1, o2));
        //如果某个Lambda表达式里只是调用一个静态方法,并且“→”前后参数的形式一致,就可以使用静态方法引用。
        //Arrays.sort(students, Student2::compareByAge);
        Arrays.sort(students, Student2::compareByAge);
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }
        System.out.println("=======================================================");
        
        Student2 t = new Student2();//创建对象来调用静态方法
        Arrays.sort(students, t::compareByHeight);
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Student2{
    private String name;
    private int age;
    private double height;
    private char sex;

    public static int compareByAge(Student2 o1, Student2 o2){ return o1.getAge() - o2.getAge(); }

    //Arrays.sort 使用的比较器需要遵循 Comparator<T> 接口规范,其 compare 方法必须返回 int 类型(表示大小关系:负数、零、正数)。
    // 如果改为 double,会导致编译错误,因为方法签名不匹配。
    public int compareByHeight(Student2 o1, Student2 o2){
        return Double.compare(o1.getHeight(), o2.getHeight()); // 使用Double.compare避免精度问题
    }
}

res

Student2(name=赵六, age=19, height=172.0, sex=男)
Student2(name=王五, age=25, height=165.0, sex=女)
Student2(name=孙七, age=27, height=170.0, sex=女)
Student2(name=李四, age=28, height=168.0, sex=男)
Student2(name=张三, age=35, height=170.0, sex=男)
Student2(name=钱八, age=36, height=168.0, sex=女)
=======================================================
Student2(name=王五, age=25, height=165.0, sex=女)
Student2(name=李四, age=28, height=168.0, sex=男)
Student2(name=钱八, age=36, height=168.0, sex=女)
Student2(name=孙七, age=27, height=170.0, sex=女)
Student2(name=张三, age=35, height=170.0, sex=男)
Student2(name=赵六, age=19, height=172.0, sex=男)

Demo3.java

java已经为我们提供了字符串按照首字母忽略大小写比较的方法:compareToIgnoreCase。
o1.compareToIgnoreCase(o2)   相当于 o1-o2
import java.util.Arrays;
import java.util.Comparator;

public class Demo3 {
    public static void main(String[] args) {
        // 目标:特定类型的方法引用。
        // 需求:有一个字符串数组,里面有一些人的名字都是,英文名称,请按照名字的首字母升序排序。
        String[] names = {"caocao","Alice", "Bob","apple", "Charlie", "David", "Eve", "Fred", "Ginny", "Harriet", "Irene", "Joseph"};

        System.out.println("a".compareToIgnoreCase("b"));//-1
        System.out.println("b".compareToIgnoreCase("a"));//1
        System.out.println("b".compareToIgnoreCase("B"));//0

        //把这个数组进行排序:Arrays.sort(names,Comparator)
        // Arrays.sort(names)://默认就是按照首字母的编号升序排序。
        // 要求:忽略首字母的大小进行升序排序(java官方默认是搞不定的,需要我们自己指定比较规则)
        /*
        Arrays.sort(names, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareToIgnoreCase(o2);//java已经为我们提供了字符串按照首字母忽略大小写比较的方法:compareToIgnoreCase
            }
        });*/

        //如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,
        //后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
        //Arrays.sort(names,(String o1, String o2) -> o1.compareToIgnoreCase(o2));
        Arrays.sort(names,(o1, o2) -> o1.compareToIgnoreCase(o2));

        //特定类型方法引用:类型名称::方法名
        Arrays.sort(names,String::compareToIgnoreCase);

        System.out.println(Arrays.toString(names));

    }
}

res

-1
1
0
[Alice, apple, Bob, caocao, Charlie, David, Eve, Fred, Ginny, Harriet, Irene, Joseph]

Demo4.java

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

public class Demo4 {
    public static void main(String[] args) {
        //理解构造器引用
        /*
        CarFactory cf = new CarFactory() {
            @Override
            public Car getCar(String name) {
                return new Car(name);
            }
        };*/

        //CarFactory cf = name -> new Car(name);

        //如果某个Lambda表达式里只是在创建对象,并且“→”前后参数情况一致,就可以使用构造器引用。
        CarFactory cf = Car::new;

        Car c1 = cf.getCar("保时捷");
        System.out.println(c1);
    }
}

interface CarFactory {
    Car getCar(String name);
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Car {
    private String name;
}

res

Car(name=保时捷)

String

StringDemo1.java

import java.util.Scanner;
public class StringDemo1 {
    public static void main(String[] args) {
        //只要是以"..."方式写出的字符串对象,会存储到字符串常量池,且相同内容的字符串只存储一份;
        //通过new方式创建字符串对象,每new一次都会产生一个新的对象放在堆内存中

        // 2、方式二:通过构造器初始化对象。
        String s2 = new String();// 不推荐
        System.out.println(s2);//““空字符串

        String s3 = new String("hello,黑马");// 不推荐
        System.out.println(s3);

        char[] chars = {'h','e','l','l','o'};
        String s4 = new String(chars);
        System.out.println(s4);

        byte[] bytes = {97,98,99,65,66,67};
        String s5 = new String(bytes);
        System.out.println(s5);

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

        //只有""给出的字符串对象放在字符串常量池,相同内容只放一个。
        String t1 = "abc";
        String t2 = "abc";
        System.out.println(t1 == t2);//true
        String t3 = new String("abc");
        String t4 = new String("abc");
        //通过new方式创建字符串对象,每new一次都会产生一个新的对象放在堆内存中
        System.out.println(t3 == t4);//false

        System.out.println("----------------------------------------");
        //调用字符串的方法,处理字符串数据。
        //简易版的登录
        String okLoginName = "admin";
        System.out.println("请输入用户名:");
        Scanner sc = new Scanner(System.in);
        String loginName = sc.next();

        //千万要注意:equals方法比较的是内容,==比较的是地址//判断字符串内容,建议用String提供的equals方法,只关心内容一样,就返回true,不关心地址
        if(loginName.equals(okLoginName)){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }

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

        System.out.println("请您输入手机号");
        String phone = sc.next();
        System.out.println("系统显示以下手机号码进入");
        //截取手机号中间四位,显示为****
        String newPhone = phone.substring(0,3) + "****" + phone.substring(7);//public string substring(int beginIndex,int endIndex)

    }
}

StringDemo2_Vertification.java

public class StringDemo2_VerificationCode {
    public static void main(String[] args) {
        System.out.println(getVerificationCode(4));
        System.out.println(getVerificationCode(6));
        System.out.println(getVerificationCode(8));
    }

    public static String getVerificationCode(int length) {
        String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        String code = "";
        for (int i = 0; i < length; i++) {
            int index = (int) (Math.random() * str.length());
            code += str.charAt(index);
        }
        return code;
    }
}

ArrayList

ArrayListDemo1.java

import java.util.ArrayList;
public class ArrayListDemo1 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");list.add("李四");list.add("王五");list.add("赵六");
        list.add("田七");list.add("老八");list.add("孙九");list.add("钱十");
        System.out.println(list);
        System.out.println(list.get(2));//获取索引为2的元素

        //删除索引为4的元素
        list.remove(4);
        list.remove("田七");
        System.out.println(list);

        //修改索引为2的元素
        list.set(2, "李华");
    }
}

res

[张三, 李四, 王五, 赵六, 田七, 老八, 孙九, 钱十]
王五
[张三, 李四, 王五, 赵六, 老八, 孙九, 钱十]

GUI

JFrameDemo1.java

import javax.swing.*;

public class JFrameDemo1 {
    public static void main(String[] args) {
        //目标:快速入门GUI Swing编程
        //1.创建一个窗口,有一个登陆按钮
        JFrame jf = new JFrame("登录窗口");
        jf.setSize(400,300);
        jf.setLocationRelativeTo(null);//居中显示。
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗口关闭的时候,程序也关闭。

        JPanel panel = new JPanel();
        jf.add(panel);

        JButton jb = new JButton("登录");
        jb.setBounds(100,100,100,50);//设置按钮的大小和位置。
        panel.add(jb);
        jf.setVisible(true);//显示窗口。
    }
}

Test.java

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class Test {
    public static void main(String[] args) {
        //1.创建一个窗口,有一个登陆按钮
        JFrame jf = new JFrame("登录窗口");
        jf.setSize(400,300);
        jf.setLocationRelativeTo(null);//居中显示。
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗口关闭的时候,程序也关闭。

        JPanel panel = new JPanel();
        jf.add(panel);

        JButton jb = new JButton("登录");
        jb.setBounds(100,100,100,50);//设置按钮的大小和位置。
        panel.add(jb);

        //给按钮添加点击事件监听器。
        //e是事件对象,里面封装了事件发生时的一些信息。
        jb.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(jf,"点击了按钮");
                jf.requestFocus(); // 重新让窗口获取焦点
            }
        });

        //需求:监听用户键盘上下左右四个按键的事件。
        //给jf窗口整体绑定按键事件
        jf.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //获取键盘按下的键值
                int keyCode = e.getKeyCode();//拿事件源头的键帽编号
                if(keyCode == KeyEvent.VK_UP){
                    System.out.println("用户按下了上键");
                }else if(keyCode == KeyEvent.VK_DOWN){
                    System.out.println("用户按下了下键");
                }else if(keyCode == KeyEvent.VK_LEFT){
                    System.out.println("用户按下了左键");
                }else if(keyCode == KeyEvent.VK_RIGHT){
                    System.out.println("用户按下了右键");
                }
            }
        });

        jf.requestFocus();//让窗口成为焦点,才可以监听键盘事件。
        jf.setVisible(true);//显示窗口。
    }
}

 

 

 

 

 

 
 

 

 

 

posted on 2025-05-23 11:59  ᶜʸᵃⁿ  阅读(11)  评论(0)    收藏  举报