面向对象高级-代码块、内部类、Lambda、方法引用

一、代码块

1、代码块是类的五大成分之一(成员变量、构造器、方法、代码块、内部类)。

2、代码块分为两种:

  • 静态代码块:
    • 格式:static{ }
    • 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。
    • 作用:完成类的初始化,例如:对静态变量的初始化赋值。
  • 实例代码块:
    • 格式:{ }
    • 特点:每次创建对象时,执行实例代码块,并在构造器前执行。
    • 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量的初始化赋值。
import java.util.Arrays;

public class CodeDemo1 {
    public static String schoolName;
    public static String[] cards=new String[54];
    //静态代码块:有static修饰,属于类,与类一起优先加载,自动执行一次
    //基本作用:可以完成对类的静态资源的初始化
    static{
        System.out.println("静态代码块");
        schoolName = "黑马程序员";
        cards[0]="大王";
        cards[1]="小王";
        //...
    }
    public static void main(String[] args)
    {
        //认识代码块,搞清楚代码块的基本作用
        System.out.println("main方法");
        System.out.println(schoolName);
        System.out.println(Arrays.toString(cards));
    }
}
public class CodeDemo2 {
    private String name;
    private String[] direction=new String[4];
    //实例代码块:无static修饰,属于对象,每次创建对象时,都会优先执行一次
    //基本作用:初始化对象的实例资源
    {
        System.out.println("实例代码块");
        name="黑马";
        direction[0]="东";
        direction[1]="南";
        direction[2]="西";
        direction[3]="北";
    }
    public static void main(String[] args)
    {
        //实例代码块
        System.out.println("main方法");
        CodeDemo2 c=new CodeDemo2();
        CodeDemo2 c2=new CodeDemo2();
    }
}

二、内部类

如果一个类定义在另一个类的内部,这个类就是内部类。

场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。

1、成员内部类

就是类中的一个普通成员,类似前面学过的普通的成员变量、成员方法。

创建成员内部类对象格式:外部类名.内部类名 对象名=new 外部类名() .new 内部类名();

成员内部类中访问其他成员的特点:

  • 成员内部类中可以直接访问外部类的实例成员、静态成员。
  • 成员内部类的实例方法中,可以直接拿到当前外部类对象,格式是:外部类名.this.成员名。
//外部类
public class Outter {
    public static String schoolName="黑马程序员";
    public static void test(){
        System.out.println("test()");
    }
    private int age;
    public void run(){
        System.out.println("run()");
    }
    //成员内部类:无static修饰,属于外部类的对象持有的
    public class Inner{
        private String name;
        //构造器
        public Inner(){
            System.out.println("Inner()"+name);
        }
        //有参数构造器
        public Inner(String name){
            this.name=name;
            System.out.println("Inner(String name)"+name);
        }
        public void show(){
            System.out.println("show");
            System.out.println(schoolName);
            test();
            System.out.println(age);
            run();
            System.out.println(this);//自己的对象
            System.out.println(Outter.this);//寄生的外部类的对象
        }

        public String getName(){
            return name;
        }

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

public class InnerClassDemo1 {
    public static void main(String[] args)
    {
        //搞清楚成员内部类的语法
        //成员内部类创建对象的格式
        //外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
        Outter.Inner oi = new Outter().new Inner();
        oi.setName("小明");
        oi.show();
        //成员内部类访问外部类成员的特点
        //1、成员内部类中可以直接访问外部类的静态成员,也可以直接访问外部类的实例成员
        //2、成员内部类的实例方法中,可以直接拿到当前寄生的外部类对象:外部类名.this
        People.Heart h=new People().new Heart();
        h.show();
    }
}

class People{
    private int heartBeat=100;
    public class Heart{
        private int heartBeat=80;
        public void show(){
            int heartBeat=200;
            System.out.println(heartBeat);//200
            System.out.println(this.heartBeat);//80
            System.out.println(People.this.heartBeat);//100
        }
    }
}

2、静态内部类

有static修饰的内部类,属于外部类自己持有。

创建静态内部类对象格式:外部类名.内部类名 对象名=new 外部类.内部类名();

静态内部类中访问外部类成员的特点:

  • 可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。
//外部类
public class Outer {
    public static String schoolName="黑马程序员";
    private int age;//实例成员
    //静态内部类:属于外部类本身持有
    public static class Inner{

        public void show() {
            System.out.println("show");
            System.out.println(schoolName);
            //System.out.println(age);//报错
        }
    }
}

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

3、局部内部类

局部内部类是定义在方法中、代码块中、构造器等执行体中(无具体意义,用来引出匿名内部类)。

4、匿名内部类

特殊的局部内部类,匿名内部类指:程序员不需要为这个类声明名字,默认有一个隐藏的名字。

格式:new 类名或接口(参数值...){重写方法}

特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。

作用:用于更方便的创建一个子类对象。

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

public class Test {
    public static void main(String[] args)
    {
        //认识匿名内部类,搞清楚其基本作用
        //匿名内部类实际上是有名字的:外部类名$编号.class
        //匿名内部类本质是一个子类,同时会立即创建一个子类对象
        Animal a=new Animal(){
            @Override
            public void cry()
            {
                System.out.println("猫是喵喵喵的叫");
            }
        };
        a.cry();
    }
}

//class Cat extends Animal{
//
//    @Override
//    public void cry() {
//        System.out.println("猫是喵喵喵的叫");
//    }
//}

通常作为一个对象参数传输给方法。

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

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

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

        start(new Swim() {
            @Override
            public void swimming() {
                System.out.println("老师狗爬式游泳");
            }
        });
    }

    //定义一个方法,可以接收老师和学生开始比赛
    public static void start(Swim s){
        System.out.println("比赛开始啦");
        s.swimming();
        System.out.println("比赛结束啦");
    }
}

interface Swim{
    void swimming();//游泳方法
}

匿名内部类应用场景:调用别人提供的方法实现需求时,这个方法正好可以让我们传输一个匿名内部类对象给其使用。

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要求必须给这个按钮添加一个点击事件监听器对象,这样就可以监听用户的点击操作,就可以做出反应
        //开发中不是我们要主动去写匿名内部类,而是用别人的功能时,别人可以让我们写一个匿名内部类,我们才会用
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("用户点击了登录按钮");
            }
        });

        win.setVisible(true);
    }
}
import java.util.Arrays;
import java.util.Comparator;

public class Test4 {
    public static void main(String[] args)
    {
        //完成给数组排序,理解其中匿名内部类的用法
        //准备一个学生类型的数组,存放6个学生对象
        Student[] students=new Student[6];
        students[0]=new Student("张三",18,170, '男');
        students[1]=new Student("李四",19,165, '女');
        students[2]=new Student("王五",20,180, '男');
        students[3]=new Student("赵六",21,175, '男');
        students[4]=new Student("孙七",22,165, '女');
        students[5]=new Student("周八",23,170, '男');

        //需求:按照年龄升序排序。可以调用sun公司写好的API直接对数组进行排序
        //public static void sort(T[] a, Comparator<T> c)
        //参数一:需要排序的数组 参数二:需要给sort声明一个比较器对象(指定排序的规则)
        //sort方法会调用匿名内部类对象的compare方法,对数组中的学生对象进行两两比较,从而实现排序
        Arrays.sort(students,new Comparator<Student>(){
            @Override
            public int compare(Student o1, Student o2) {
                //指定排序规则
                //如果你认为左边对象 大于 右边对象 那么返回正整数
                //如果你认为左边对象 小于 右边对象 那么返回负整数
                //如果两边相等那么返回0
//                if(o1.getAge() > o2.getAge()){
//                    return 1;
//                }else if(o1.getAge() < o2.getAge()){
//                    return -1;
//                }else{
//                    return 0;
//                }
               // return o1.getAge() - o2.getAge();//按照年龄升序
                return o2.getAge() - o1.getAge();//按照年龄降序
            }
        });

        //遍历数组中的学生对象并输出
        for (int i = 0; i < students.length; i++) {
            Student s=students[i];
            System.out.println(s);
        }
    }
}

三、函数式编程

1、Java中的函数(即Lambda表达式)

JDK8开始引入了Lambda表达式,替代函数式接口的匿名内部类,从而让程序更简洁,可读性更好。

Lambda表达式的格式:(形式参数列表)->{匿名内部类被重写的方法体代码}

什么是函数式接口?

  • 有且仅有一个抽象方法的接口。
  • 注意:将来见到的大部分函数式接口,上面都可能会有一个@Functionallnterface的注解,该注解用于约束当前接口必须是函数式接口。

Lambda表达式的简化规则:

  • 参数类型可以全部省略不写
  • 如果只有一个参数,参数类型省略的同时"( )"也可以省略,但多个参数不能省略"( )"
  • 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号,如果这行代码是return语句,也必须去掉return
public class LambdaDemo1 {
    public static void main(String[] args) {
        //认识Lambda表达式,搞清楚其基本作用
        Animal a=new Animal() {
            @Override
            public void cry() {
                System.out.println("猫是喵喵叫的");
            }
        };
        a.cry();
        //Lambda并不是可以简化全部的匿名内部类,Lambda只能简化函数式接口的匿名内部类
        Swim s=()->{
            System.out.println("Lambda简化的匿名内部类");
        };
        s.swimming();
    }
}

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

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

import java.util.Arrays;

public class LambdaDemo2 {
    public static void main(String[] args) {
        //用Lambda表达式简化实际示例
        Student[] students=new Student[6];
        students[0]=new Student("张三",18,170, '男');
        students[1]=new Student("李四",19,165, '女');
        students[2]=new Student("王五",20,180, '男');
        students[3]=new Student("赵六",21,175, '男');
        students[4]=new Student("孙七",22,165, '女');
        students[5]=new Student("周八",23,170, '男');

        //需求:按照年龄升序排序。可以调用sun公司写好的API直接对数组进行排序
//        Arrays.sort(students,new Comparator<Student>(){
//            @Override
//            public int compare(Student o1, Student o2) {
//                return o2.getAge() - o1.getAge();//按照年龄降序
//            }
//        });

//        Arrays.sort(students,(Student o1, Student o2)->{
//            return o2.getAge() - o1.getAge();//按照年龄降序
//        });

//        Arrays.sort(students,(o1,o2)->{
//            return o2.getAge() - o1.getAge();//按照年龄降序
//        });

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

        //遍历数组中的学生对象并输出
        for (int i = 0; i < students.length; i++) {
            Student s=students[i];
            System.out.println(s);
        }
    }
}

2、方法引用

JDK8中提供了一些常用的方法引用,可以用"::"引用运算符简化Lambda表达式

静态方法的引用

格式:类名::静态方法名

 使用场景:如果某个Lambda表达式里只是调用一个静态方法,并且"->"前后参数的形式一致,就可以使用静态方法引用。

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

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

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

    public int compareByHeight(Student o1, Student o2){
        //按照身高比较
        return Double.compare(o1.getHeight(), o2.getHeight());
    }

}

import java.util.Arrays;

public class Demo1 {
    public static void main(String[] args) {
        // 静态方法引用:演示一个场景
        test();
    }
    public static void test(){
        Student[] students=new Student[6];
        students[0]=new Student("张三",18,170, '男');
        students[1]=new Student("李四",19,165, '女');
        students[2]=new Student("王五",20,180, '男');
        students[3]=new Student("赵六",21,175, '男');
        students[4]=new Student("孙七",22,165, '女');
        students[5]=new Student("周八",23,170, '男');

        //需求:按照年龄升序排序。可以调用sun公司写好的API直接对数组进行排序
        Arrays.sort(students,(o1, o2)->o2.getAge() - o1.getAge());

        //静态方法引用:类名:静态方法名
        Arrays.sort(students,Student::compareByAge);

        //遍历数组中的学生对象并输出
        for (int i = 0; i < students.length; i++) {
            Student s=students[i];
            System.out.println(s);
        }
    }
}

实例方法的引用

格式:对象名::实例方法名

使用场景:如果某个Lambda表达式里只是通过对象名称调用一个实例方法,并且"->"前后参数的形式一致,就可以使用实例方法引用。

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

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

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

    public int compareByHeight(Student o1, Student o2){
        //按照身高比较
        return Double.compare(o1.getHeight(), o2.getHeight());
    }

}

import java.util.Arrays;

public class Demo2 {
    public static void main(String[] args) {
        // 实例方法引用:演示一个场景
        test();
    }
    public static void test(){
        Student[] students=new Student[6];
        students[0]=new Student("张三",18,170, '男');
        students[1]=new Student("李四",19,165, '女');
        students[2]=new Student("王五",20,180, '男');
        students[3]=new Student("赵六",21,175, '男');
        students[4]=new Student("孙七",22,165, '女');
        students[5]=new Student("周八",23,170, '男');

        //需求:按照年龄升序排序。可以调用sun公司写好的API直接对数组进行排序
        Student t=new Student();
        Arrays.sort(students,(o1, o2)->o2.getAge() - o1.getAge());

        //Arrays.sort(students,Student::compareByHeight);

        //遍历数组中的学生对象并输出
        for (int i = 0; i < students.length; i++) {
            Student s=students[i];
            System.out.println(s);
        }
    }
}

特定类的方法引用

格式:特定类的名称::方法名

使用场景:如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。

构造器引用

格式:类名::new

使用场景:如果某个Lambda表达式里只是在创建对象,并且"->"前后参数情况一致,就可以使用构造器引用。

四、常见API

1、String

String是什么,有什么用?

  • String代表字符串,它的对象可以封装字符串数据,并提供了很多方法完成对字符串的处理。

String类创建对象封装字符串数据的方式有几种?

  • 方式一:直接使用双引号"..."。
  • 方式二:new String类,调用构造器初始化字符串对象。

Attention:只要以双引号方式创建字符串对象,会存储到字符串常量池中,且相同字符串只会储存一次。通过new关键字创建字符串对象,每new一次,都会产生一个新的对象放在堆内存中。

import java.util.Scanner;

public class StringDemo1 {
    public static void main(String[] args) {
        //掌握创建字符串对象,封装要处理的字符串数据,调用String提供的方法处理字符串
        //1、推荐方式一:直接""就可以创建字符串对象,封装字符串数据
        String s1 = "hello,黑马";
        System.out.println(s1);
        System.out.println(s1.length());//处理字符串的方法
        //2、方式二:通过构造器初始化对象
        String s2 = new String();//不推荐
        System.out.println(s2);//输出:空字符串

        String s3 = new String("abc");//不推荐
        System.out.println(s3);

        char ch[] = {'a','b','c'};
        String s4 = new String(ch);
        System.out.println(s4);

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

        //只有双引号给出的字符串对象放在字符串常量池,相同内容只放一个
        String t1="abc";
        String t2="abc";
        System.out.println(t1==t2);

        String t3=new String("abc");
        String t4=new String("abc");
        System.out.println(t3==t4);

        //调用字符串方法,处理字符串数据
        //简易版登录
        String username = "admin";
        System.out.println("请输入您的登录名称:");
        Scanner sc = new Scanner(System.in);
        String name = sc.next();
        //字符串对象的内容比较,千万不要用==默认比较地址,字符串对象的内容一样时地址不一定一样
        //判断字符串内容,建议大家用String提供的equals方法,只关心内容一样,就返回true,不关心地址
        if(name.equals(username)){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }

        //13546590922==》135****9022
        System.out.println("请您用手机号码登录:");
        String phone = sc.next();

        System.out.println("系统显示以下手机号码进入:");
        String newPhone = phone.substring(0,3)+"****"+phone.substring(7);
        System.out.println(newPhone);
    }
}

String提供的常用方法

方法名说明
public int length()获取字符串长度返回(字符个数)
public char cahrAt(int index)获取某个索引位置处的字符返回
public char[ ] toCharArray()将当前字符串转换成字符数组返回
public boolean equals(Object anObject)判断当前字符串与另一个字符串的内容是否一样,一样返回true
public boolean equalsIgnoreCase(String anotherString)判断当前字符串与另一个字符串的内容是否一样(忽略大小写)
public String substring(int beginIndex,int endIndex)根据开始和结束索引进行截取,得到新的字符串(包前不包后)
public String substring(int beginIndex)从传入的索引处截取,截取到末尾,得到新的字符串返回
public String replace(CharSequence target,CharSequence replacement)使用新值,讲字符串中的旧值替换,得到新的字符串
public boolean containt(CharSequence s)判断字符串中是否包含了某个字符串
public boolean startsWith(String prefix)判断字符串是否以某个字符串内容为开头,是则返回true
public String[ ] split(String regex)把字符串按照某个字符串内容分割,返回字符串数组回来
public class StringDemo2 {
    public static void main(String[] args) {
        //生成验证码
        String code =getCode(4);
        System.out.println(code);

        System.out.println(getCode(6));
    }

    //帮我生成指定位数的验证码返回,每位可能是大小写字母或者数字
    //帮我用String变量记住全部要用到的字符
    public static String getCode(int n){
        //1、定义一个变量记住所有的字符
        String source = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        //2、定义一个变量用于记住验证码的随机字符
        String code = "";
        //3、循环n次,每次生成一个随机字符,拼接成字符串
        for (int i = 0; i < n; i++) {
            //4、随机一个索引
            int index = (int)(Math.random()*source.length());
            //5、根据索引获取字符,拼接成字符串
            code += source.charAt(index);
        }
        //6、返回
        return code;
    }
}

 2、ArrayList

ArrayList代表集合,是一种容器,用来装数据的,类似于数组。

集合相对于数组,容量大小可变,功能丰富,开发中用的更多。

ArrayList是什么?怎么使用?

  • 是集合中最常用的一种,ArrayList是泛型类,可以约束存储的数据类型。
  • 创建对象:调用无参数构造器public ArrayList( )初始化对象
  • 调用增删改查数据的方法
常用方法说明
public ArrayList()创建一个空的集合对象
public boolean add(E e)在集合的末尾添加一个指定的元素,并返回true
public void add(int index,E element)在集合的指定索引位置添加一个指定的元素,并返回true
public E get(int index)返回指定索引位置的元素
public int size()返回集合中元素的个数
public E remove(int index)删除指定索引位置的元素,并返回被删除的元素
public boolean remove(Object o)删除指定元素,并返回删除是否成功
public E set(int index,E element)修改指定索引位置的元素,并返回被修改的元素
import java.util.ArrayList;

public class ArrayListDemo1 {
    public static void main(String[] args) {
        //掌握ArrayList的基本使用
        //创建ArrayList对象,代表一个集合容器
        ArrayList<String> list = new ArrayList<>();//泛型定义集合
        //添加数据
        list.add("hello");
        list.add("world");
        list.add("java");
        System.out.println(list);
        //查看数据
        System.out.println(list.get(0));
        System.out.println(list.get(1));
        System.out.println(list.get(2));
        //遍历集合
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
        //删除数据
        list.remove(1);//根据索引删除
        System.out.println(list);
        System.out.println(list.remove("java"));//根据元素删除
        System.out.println(list);
        //修改数据
        list.set(0,"java");
        System.out.println(list);
    }
}

五、GUI编程

什么是GUI编程?

  • GUI,全称Graphical User Interface,是指图形用户界面。
  • 通过图形元素(如窗口、按钮、文本框等)与用户进行交互。
  • 与命令行界面(CLI)相比,GUI更加直观、友好。

为什么学习GUI编程?

  • 增强用户体验
  • 广泛应用于桌面应用程序开发
  • Java提供了强大的GUI编程支持

Java的GUI编程包

  • AWT(Abstract Window Toolkit)
    • 提供了一组原生的GUI组件,依赖于操作系统的本地窗口系统
  • Swing
    • 基于AWT,提供了更丰富的GUI组件,轻量级组件,不依赖于本地窗口系统

常见的Swing组件

  • JFrame:窗口
  • JPanel:用于组织其他组件的容器
  • JButton:按钮组件
  • JTextField:输入框
  • JTable:表格
  • ...
import javax.swing.*;

public class JFrameDemo1 {
    public static void main(String[] args){
        //快速入门GUI Swing的编程
        //1、创建一个窗口,有一个登录按钮
        JFrame jf=new JFrame();

        JPanel jp=new JPanel();//创建一个面板
        jf.add(jp);//将面板添加到窗口

        jf.setSize(400,300);//设置窗口大小
        jf.setLocationRelativeTo(null);//设置窗口居中
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口退出程序

        JButton btn=new JButton("登录");//创建一个按钮
        btn.setBounds(100,100,100,50);//设置按钮的位置和宽高
        jp.add(btn);//将按钮添加到面板
        jf.setVisible(true);//显示窗口
    }
}

布局管理器(Layout Manager)它们可以决定组件在容器中的布局方式,避免了手动设置每个组件的位置和大小,从而简化了GUI设计过程。

常见的布局管理器

  • FlowLayout:按照水平方向从左到右排列组件,当一行排满时,自动切换到下一行
  • 特点:默认居中对齐,可以设置左对齐或右对齐;适用于需要简单排列的场景。
  • BorderLayout:将容器分为5个区域,North、South、East、West、Center,每个区域只能添加一个组件。
  • 特点:适用于要在特定区域布局组件的场景;中间的组件会自动填充剩余的空间。
  • GridLayout:将容器按照指定的行数和列数进行布局,每个组件占一个单元格,所有组件大小相同。
  • 特点:适用于需要将组件均分到容器中的场景;行和列的数量可以指定。
  • BoxLayout:将容器按照单一水平或垂直方向排列组件,每个组件占一个单元格,所有组件大小相同。
  • 特点:适用于需要沿单一方向排列组件的场景;可以添加垂直或水平方向的间隔来调整组件间距。

事件处理:GUI编程中,事件的处理是通过事件监听器(Event Listener)来完成的。

常用的时间监听器对象

  • 点击事件监听器 ActionListener
  • 按键事件监听器 KeyListener
  • 鼠标行为监听器 MouseListener
  • ...

事件的几种常见写法

1、直接提供实现类,用于创建事件监听对象。

2、直接使用匿名内部类的对象,代表事件监听对象。

3、自定义窗口,让窗口对象实现事件接口。

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)
    {
        //认识GUI的事件处理机制
        //1、创建一个窗口,有一个登录按钮
        JFrame jf=new JFrame();

        JPanel jp=new JPanel();//创建一个面板
        jf.add(jp);//将面板添加到窗口

        jf.setSize(400,300);//设置窗口大小
        jf.setLocationRelativeTo(null);//设置窗口居中
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口退出程序

        JButton btn=new JButton("登录");//创建一个按钮
        btn.setBounds(100,100,100,50);//设置按钮的位置和宽高
        jp.add(btn);//将按钮添加到面板

        //给按钮绑定点击事件监听器对象
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //一旦点击了按钮,底层触发这个方法执行
                //e 是事件对象,封装了事件相关信息
                JOptionPane.showMessageDialog(jf,"用户点击了登录按钮");
            }
        });

        //需求:监听用户键盘上下左右四个按键的事件:
        //给jf窗口整体绑定按键事件
        jf.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //一旦用户按下了键盘上的某个键,底层触发这个方法执行
                //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.setVisible(true);//显示窗口
        //让窗口成为焦点
        jf.requestFocus();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值