------------java基础d8--01---类中的成分-代码块---------------------------------------------------------------------
高级面向对象编程:代码块、内部类、函数式编程、常用API、GUI编程;
- 代码块是类的五大成分之一:即成员变量、构造器、方法、代码块、内部类;
- 成员变量:描述成员对象或类一些属性信息;
- 构造器:初始化对象或者为对象直接赋值的(构造方法/编程思想)
- 方法: 做功能描述行为的。
- 代码块:分为两种,按照有无static区分:
-
静态代码块:有static
- 格式:static { }
- 特点:类加载的时候自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。
- 作用:完成类的初始化,例如:对静态变量的初始化赋值。
javapackage com.itheima.code; public class CodeDemo1 { public static String schoolname; public static String[] cards = new String[54]; //静态代码块:有static修饰,属于类,与类一起优先加载,自动执行一次。 static{ System.out.println("静态代码块执行了"); schoolname = "张三"; //存四个花色 String[] colors = {"♦","♣","♥","♠"}; //存13个牌 String[] numbers = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"}; int index = 0; for (int i = 0; i < numbers.length; i++) { for (int j = 0; j < colors.length; j++) { cards[index] = colors[j] + numbers[i]; index++; } } cards[index] = "小王"; cards[index+1] = "大王"; } public static void main(String[] args) { //目标:认识代码块,搞清楚代码块的基本作用。 System.out.println("main方法执行了"); System.out.println(schoolname); for (int i = 0; i < cards.length; i++) { System.out.print(cards[i]); if((i+1) % 4 == 0){ System.out.println(); } } } } -
实例代码块:无static (也叫构造代码块)
- 格式: { }
- 特点:每次创建对象时,执行实例代码块,并在构造器前执行。
- 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化赋值。
javapackage com.itheima.code; public class CodeDemo2 { private static String name; private String[] directors = new String[4]; //实例代码块:无static修饰,属于对象,每次创建对象时,都会优先执行一次。 //基本作用:初始化对象的实例资源。 { System.out.println("实例代码块执行了"); name = "默认名字ct"; directors[0] = "N"; directors[1] = "S"; directors[2] = "E"; directors[3] = "W"; } public static void main(String[] args) { //实例代码块; System.out.println("main方法执行了"); CodeDemo2 c1 = new CodeDemo2(); CodeDemo2 c2 = new CodeDemo2(); CodeDemo2 c3 = new CodeDemo2(); } }
-
------------java基础d8--02---内部类-成员内部类-静态内部类-局部内部类------------------------------------
内部类:
- 如果一个类定义在另一个类的内部,这个类就是内部类;
- 场景:当一个类的内部,包含了一个完整的事物,切这个事物没必要单独设计时,就可以把这个事物设计成内部类。
- 分为四类:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类:
-
就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法。
1.javapublic class Outer{ //成员内部类 public class Inner{ } }Outer.Inner inner = new Outer().new Inner();//创建的时候不一样。其他用的时候都是一样的。(别的类也可以继承它,它也可以继承别人)
2. 创建的时候格式:-
外部类名。内部类名 对象名 = new 外部类()。new 内部类();
-
成员内部类中访问其他成员的特点:
- 可以直接访问外部类的实例成员、静态成员
- 可以拿到当前外部类对象,格式:外部类名。this
-
java
//Outer类和其成员内部类Inner
package com.itheima.innerclass;
public class Outer {
public static String name = "张三";
static int age = 18;
public static void test(){
System.out.println("Outer类的静态方法test()执行了");
}
//定义一个成员内部类;;没有static修饰,属于外部类的对象持有的。
public class Inner{
public void show(){
System.out.println("Outer类的Inner内部类的show()方法执行了");
System.out.println("Outer类的成员变量name的值是:" + name);
test();//调用外部类的静态方法
System.out.println("Outer类的静态变量age的值是:" + age);
}
}
public Outer(String name) {
Outer.name = name;
}
public Outer() {
}
public static String getName() {
return name;
}
public static void setName(String name) {
Outer.name = name;
}
}
java
//主函数和其类People和其成员内部类Heart
package com.itheima.innerclass;
public class InnweClassDemo1 {
public static void main(String[] args) {
//目标:搞清楚成员内部类的语法;
//成员内部类创建对象的格式:
//外部类名称.内部类名称 对象名 = new 外部类名称.new 内部类名称();
Outer.Inner inner = new Outer().new Inner();
inner.show();
//成员内部类访问外部类成员的特点(拓展)
//1、成员内部类可以访问外部类的静态成员。也可以直接访问外部类的实例成员。
//2、成员内部类的实例方法中,可以直接拿到当前寄生的外部类对象:外部类名.this
// 因为直接用this 是拿内部类本身的对象,所以要拿外部类对象,用外部类名.this
System.out.println("===================================================");
People.Heart heart = new People().new Heart();
heart.show();
//
}
}
class People{
private int hearBeat = 100;
public class Heart{
private int hearBeat = 200;
public void show(){
System.out.println("hearBeat心脏跳动中..." + hearBeat); //200
System.out.println("this.hearBeat心脏跳动中..." + this.hearBeat); //200
System.out.println("People.this.hearBeat心脏跳动中..." + People.this.hearBeat); //100
}
}
}
小结:
- 成员内部类是什么?如何创建其对象?
- 就是类中的一个普通成员,类似前面我们学过的普通成员变量、成员方法
- 外部类名。内部类名 对象名 = new 外部类()。new内部类();
- 成员内部类的实例方法中,访问其他成员有啥特点?
- 可以直接访问外部类的实例成员、静态成员
- 可以拿到当前外部类对象,格式:外部类名。this
静态内部类
-
有static修饰的内部类,属于外部类自己持有
-
格式:
javapublic class Outer{ //静态内部类 public static class Inner{ } } /外部类名。内部类名 对象名 = new 外部类。内部类(); Outer.Inner in = new Outer.Inner();
小结:
- 什么是静态内部类?如何创建对象?有啥特点?
- 有static修饰的内部类;
- 外部类名。内部类名 对象名 = new 外部类名。内部类名 ();
- 可以直接访问外部类的静态成员变量,不能直接访问外部类的实例成员。
局部内部类:
比如在方法、代码块、构造器中里面定义一个内部类甚至接口;作用不大,看看就好。
------------java基础d8--03---匿名内部类-认识-使用形式---------------------------------------------------------
匿名内部类:
-
一种特殊的局部内部类;
- 所谓匿名,就是指程序员不需要为这个类声明名字,默认有个隐藏的名字。
-
格式:
-
new 类或者接口(参数,可有可无){
类体(一般是方法重写);
};
javanew Animal(){ @Override public void cry(){ } }; //Animal是一个类名或者接口名,因为匿名内部类就写在某个类或者接口中,这个Animal就是这个类或接口的名字代码:
-
-
特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
-
作用:用于更方便的创建一个子类对象。
小结:
-
匿名内部类的书写格式:
-
代码:
javanew Animal(){ @Override public void cry(){ } }; //Animal是一个类名或者接口名,因为匿名内部类就写在某个类或者接口中,这个Animal就是这个类或接口的名字
-
-
匿名内部类有啥特点?
- 匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
-
匿名内部类有啥基本作用?
- 可以更方便的创建一个子类对象。
常见使用形式:
- 作为一个对象参数传输给方法:
- 需求:学生,老师要参加游泳比赛。
java
//一般写代码:
package com.itheima.innerclass3;
public class Test2 {
public static void main(String[] args) {
//目标:搞清楚匿名内部类的使用形式(语法):通常可以作为一个对象参数传输给方法使用。
//需求:学生,老师都要参加游泳比赛。
Swim s = new Student();
start(s);
Swim t = new Teacher();
start(t);
}
public static void start(Swim s){
System.out.println("------------------------------------------开始游泳");
s.swimming();
System.out.println("结束游泳------------------------------------------");
}
}
class Teacher implements Swim{
@Override
public void swimming() {
System.out.println("老师游泳狗刨式");
}
}
class Student implements Swim{
@Override
public void swimming() {
System.out.println("学生游泳蛙泳式");
}
}
interface Swim{
public void swimming();
}
java
//匿名内部类代码:
package com.itheima.innerclass3;
public class Test22 {
public static void main(String[] args) {
swim s = new swim() {
@Override
public void swimming() {
System.out.println("学生游泳蛙泳式");
}
};
test(s);
swim t = new swim() {
@Override
public void swimming() {
System.out.println("老师游泳狗刨式");
}
};
test(t);
}
public static void test(swim s){
System.out.println("开始游泳------------------------------------------------------------------------------------------------------");
s.swimming();
System.out.println("---------------------------------------------------------------------------------------------------结束游泳---");
}
}
interface swim{
public void swimming();
}
------------java基础d8--04---匿名内部类-使用场景------------------------------------------------------------------
调用别人提供的方法实现需求时,这个方法正好可以让我们传输一个匿名内部类对象给其使用。
java
//比如可以涨么写。------------------------------------------------------------------------------------------------------------------------------------------------
package com.itheima.innerclass3;
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(400,300); //设置桌子的的宽高、大小
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 ClickListener0());
win.setVisible(true);
}
}
class ClickListener0 implements ActionListener {
public int index = 0;
@Override
public void actionPerformed(ActionEvent e) {
index++;
System.out.println("第"+ index +"次点击了登录按钮");
}
}
java
// 也可以用匿名内部类写、(匿名内部类的简化写法)------------------------------------------------------------------
package com.itheima.innerclass3;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test33 {
public static void main(String[] args) {
//目标:搞清楚几个匿名内部类的使用场景。
//需求:创建一个登录窗口,窗口上只有一个登录按钮
JFrame win = new JFrame("登录窗口"); //创建一个桌子
win.setSize(400,300); //设置桌子的的宽高、大小
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("点击了登录按钮");
}
});
btn.addActionListener(e ->System.out.println("点击了登录按钮")); //等同于上边匿名内部类,简写。学匿名内部类还有个好处,简化代码。
win.setVisible(true);
}
}
------------java基础d8--05---匿名内部类-另一个应用场景---------------------------------------------------------
对数组中的信息进行排序:
先定义一个学生类,存放学生信息:
java
package com.itheima.innerclass3;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestStudent {
private String name;
private int age;
private double height;
private String sex;
}
然后main函数,先存储一个数组,存一批数据,然后用sun公司的sort方法重写一下,用匿名内部类进行排序:
java
package com.itheima.innerclass3;
import java.util.Arrays;
import java.util.Comparator;
public class Test4 {
public static void main(String[] args) {
//目标:安城数组排序,并理解其中匿名内部类的用法
//准备一个学生类型的数组,存放六个学生对象
TestStudent[] students = new TestStudent[6];
//去网上找几个美女的信息存进来,美女可以是女明星、女歌手、女演员
students[0] = new TestStudent("杨幂", 35, 166.5, "女");
students[1] = new TestStudent("刘诗诗", 34, 168.0, "女");
students[2] = new TestStudent("赵丽颖", 33, 165.0, "男");
students[3] = new TestStudent("迪丽热巴", 29, 168.5, "女");
students[4] = new TestStudent("杨紫", 28, 163.0, "男");
students[5] = new TestStudent("殷素素", 35, 171.5, "女");
//需求:按照年龄升序排序,可以调用sun公司写好的API直接对数组进行排序;
// public static void sort(int[] a)
// Arrays.sort( students); //因为不知道按照哪个数据进行排序。
// public static void sort(T[] a,Comparator <T> c)
// 参数一T:T代表要排序的数组
// 参数二Comparator: 需要给sort声明一个比较器对象(指定排序的规则,按照什么排呢?)
//sort方法内部会调用匿名内部类对象的compare方法,对数组中的学生对象进行两两比较,从而实现排序。
Arrays.sort(students, new Comparator<TestStudent>() {
@Override
public int compare(TestStudent o1, TestStudent 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();//简化,上边的if判断,因为o1减去o2,那么o1大就是会返回正整数,o1小就返回负整数。
}
});
//排一下按照身高来的。
Arrays.sort(students, new Comparator<TestStudent>() {
@Override
public int compare(TestStudent o1, TestStudent o2) {
//如何指定排序规则呢?
//如果认为左边对象 大于 右边对象,那么返回正整数。
//如果认为左边对象 小于 右边对象,那么返回负整数。
//如果认为左边对象 等于 右边对象,那么返回0。
if (o1.getHeight() > o2.getHeight()){
return 1;
} else if (o1.getHeight() < o2.getHeight()) {
return -1;
}else return 0;
// return o1.getHeight() - o2.getHeight(); 搞不了,因为height是double,不一定返回正整数。
}
});
//打印遍历数组。
for (int i = 0; i < students.length; i++) {
TestStudent s = students[i];
System.out.println("姓名:" + s.getName() + ",\t年龄:" + s.getAge() + ",\t身高:" + s.getHeight() + ",\t性别:" + s.getSex());
}
}
}
------------java基础d8--06---函数式编程-Lambda的认识---------------------------------------------------------
JDK8开始,一种函数式编程:Lambda
-
此"函数"类似于数学中的函数(强调做什么),只要输入的数据一致返回的结果也是一致的;
- 比如2x+1;输入x=1那么输出的结果就是3;
- Java中的函数(Lambda表达式):(x)- > 2x+1
-
函数式编程解决了什么问题?
- 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好。
-
JDK8开始新增的一种语法形式,表示函数;
- 可以用于替代某些匿名内部类......
- 只能简化函数式接口的匿名内部类(有且仅有一个抽象方法的接口,才能替代)
java(被重写方法的形参列表)->{ 被重写方法的方法体代码。 }1
3. 注意:将来我们见到的大部分函数式接口,上边都可能会有一个@FunCtionalInterface的注解,该注解用于约束当前接口必须是函数式接口;-
例子:
javapackage com.itheima.lambda; public class LambdaDemo1 { public static void main(String[] args) { //目标:认识Lambda表达式,搞清楚其基本作用; Animal a = new Animal() { @Override public void eat() { System.out.println("吃吃吃"); } }; a.eat(); Swim s = new Swim() { @Override public void swimming() { System.out.println("游泳去咯,欧拉欧拉~"); } }; s.swimming(); Swim s1 = () -> { //java可以根据上下文推断出,原来的代码长上边那个样子,所以可行;1、根据前面Swim来推断出是哪个接口,2、根据方法参数,确定是接口的这个方法,然后就可以重写出原来的代码。 System.out.println("哥们游泳,呀哈呀哈~"); }; s1.swimming(); } } //抽象类,这个不能用Lambda表达式--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- abstract class Animal{ public abstract void eat(); } //函数式接口:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @FunctionalInterface //声明函数式接口的注解,如果有两个方法或者不是接口,会报错。 interface Swim{ void swimming(); // void run(); //报错 }1
- 可以用于替代某些匿名内部类......
小结:
- 什么是函数式编程?有什么好处?
- 使用Lambda函数替代某些匿名 内部类对象,从而让程序更简洁,可读性更好;
- Lambda表达式是啥?有什么用?怎么写?
- JDK8新增的一种语法,代表函数,可以用于替代并简化函数式接口的匿名内部类;
- 什么样的接口是函数式接口?怎么确保一个接口必须是函数式接口?
- 只有一个抽象方法的接口就是函数式接口。
- 在接口上加上@FuncationalInterface注解即可。
行内很多程序员称呼Java中的方法为函数,是不专业的,C语言中是这样的,但是Java中的方法就是方法,Java中的函数就是指Lambda函数。
------------java基础d8--07---函数式编程-Lambda的实例和省略规则------------------------------------------
-
Lambda的省略规则:
- 参数类型全部可以省略不写
- 如果只有一个参数,参数类型省略的同时"()"也可以省略,但多个参数不能省略"()"
- 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略";"如果这行代码是return语句,也必须去掉return;
-
省略例子:注意,简写代码可遇而不可求
java//1、------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ //一般写法: // Arrays.sort(students, new Comparator<TestStudent>() { // @Override // public int compare(TestStudent o1, TestStudent o2) { // return o1.getAge() - o2.getAge();//简化,上边的if判断,因为o1减去o2,那么o1大就是会返回正整数,o1小就返回负整数。 // } // }); //用Lambda表达式简写: // Arrays.sort(students,(TestStudent o1, TestStudent o2) -> { // return o1.getAge() - o2.getAge();//简化,上边的if判断,因为o1减去o2,那么o1大就是会返回正整数,o1小就返回负整数。 // }); //Lambda精简版: Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge()); //2、------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ //一般写法 // btn.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { //直接搞一个匿名内部类。 // System.out.println("点击了登录按钮"); // } // }); //用Lambda表达式简写: // btn.addActionListener((ActionEvent e) ->{ //直接搞一个匿名内部类。 // System.out.println("点击了登录按钮"); // }); //Lambda精简版: btn.addActionListener(e ->System.out.println("点击了登录按钮")); //等同于上边匿名内部类,简写。学匿名内部类还有个好处,简化代码。 //1、省略了参数类型2、只有一个参数,可以省略()3、只有一行代码,那么大括号可以省略,同时必须省略分号";";同时如果带着return也要省略。以下是上边两个例子的补全代码:
java
package com.itheima.lambda;
import com.itheima.innerclass3.TestStudent;
import javax.swing.*;
import java.util.Arrays;
public class LambdaDemo2 {
public static void main(String[] args) {
//目标:用Lambda表达式简化实际实例
Test1();
Test2();
}
public static void Test1(){
TestStudent[] students = new TestStudent[6];
//去网上找几个美女的信息存进来,美女可以是女明星、女歌手、女演员
students[0] = new TestStudent("杨幂", 35, 166.5, "女");
students[1] = new TestStudent("刘诗诗", 34, 168.0, "女");
students[2] = new TestStudent("赵丽颖", 33, 165.0, "男");
students[3] = new TestStudent("迪丽热巴", 29, 168.5, "女");
students[4] = new TestStudent("杨紫", 28, 163.0, "男");
students[5] = new TestStudent("殷素素", 35, 171.5, "女");
// Arrays.sort(students, new Comparator<TestStudent>() {
// @Override
// public int compare(TestStudent o1, TestStudent o2) {
// return o1.getAge() - o2.getAge();//简化,上边的if判断,因为o1减去o2,那么o1大就是会返回正整数,o1小就返回负整数。
// }
// });
//简化:匿名内部类
// Arrays.sort(students,(TestStudent o1, TestStudent o2) -> {
// return o1.getAge() - o2.getAge();//简化,上边的if判断,因为o1减去o2,那么o1大就是会返回正整数,o1小就返回负整数。
// });
//Lambda精简版:
Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());
//打印遍历数组。
for (int i = 0; i < students.length; i++) {
TestStudent s = students[i];
System.out.println("姓名:" + s.getName() + ",\t年龄:" + s.getAge() + ",\t身高:" + s.getHeight() + ",\t性别:" + s.getSex());
}
}
public static void Test2(){
//需求:创建一个登录窗口,窗口上只有一个登录按钮
JFrame win = new JFrame("登录窗口"); //创建一个桌子
win.setSize(400,300); //设置桌子的的宽高、大小
win.setLocationRelativeTo(null); //居中显示
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
win.add(panel); //给桌子加一个桌布
JButton btn = new JButton("登录");
panel.add(btn); //把按钮加到桌布上去。
//正常写法
// btn.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) { //直接搞一个匿名内部类。
// System.out.println("点击了登录按钮");
// }
// });
//用Lambda表达式简写:
// btn.addActionListener((ActionEvent e) ->{ //直接搞一个匿名内部类。
// System.out.println("点击了登录按钮");
// });
//Lambda进一步简化:
btn.addActionListener(e ->System.out.println("点击了登录按钮")); //等同于上边匿名内部类,简写。学匿名内部类还有个好处,简化代码。
//1、省略了参数类型2、只有一个参数,可以省略()3、只有一行代码,那么大括号可以省略,同时必须省略分号";";同时如果带着return也要省略。
win.setVisible(true);
}
}
------------java基础d8--08---函数式编程-方法引用-静态方法引用---------------------------------------------
方法引用还可以简化Lambda;
方法引用:
-
静态方法的引用
-
格式:类名::静态方法
-
使用场景:某个Lambda表达式只是调用一个静态方法,并且"➡"前后参数的形式一致,就可以使用静态方法引用。
-
代码:
java//接上节课,Lambda表达式精简版: Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge()); 在类中声明一个静态方法: public static int compareByAge(TestStudent o1, TestStudent o2){ return o1.getAge() - o2.getAge(); } //然后就可以变成: Arrays.sort(students, (o1, o2) -> TestStudent.compareByAge(o1, o2)); //此时满足方法引用的静态方法引用:这里就相当于最上边的代码了。 Arrays.sort(students, TestStudent::compareByAge);
-
-
实例方法的引用
-
特定类型方法的引用
-
构造器引用
------------java基础d8--09---函数式编程-方法引用-实例方法引用---------------------------------------------
方法引用:
-
静态方法的引用
-
实例方法的引用
-
格式:对象名::实例方法;
-
场景:如果某个Lambda表达式只是通过对象名称调用一个实例方法,并且"➡"前后参数的形式一致,就可以使用实例方法引用。
-
代码:
java//先在学生类里面搞一个实例方法: public int compareByHeight(TestStudent o1, TestStudent o2){ return Double.compare(o1.getHeight(), o2.getHeight()); //return后边这一块,是比较double类型的。 } //然后新建一个对象,调用一下,Lambda表达式就变成了: TestStudent t = new TestStudent(); Arrays.sort(students,(o1, o2) -> t.compareByHeight(o1, o2)); //此时满足实例方法引用,精简版: Arrays.sort(students,t::compareByHeight);
-
-
特定类型方法的引用
-
构造器引用
------------java基础d8--10---函数式编程-方法引用-特定类型的方法引用------------------------------------
-
静态方法的引用
-
实例方法的引用
-
特定类型方法的引用
-
格式:特定类的名称::方法
-
使用场景:如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
-
代码:
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) -> {return o1.compareToIgnoreCase(o2);}); //Lambda精简版:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Arrays.sort(names, (o1,o2)->o1.compareToIgnoreCase(o2)); //特定类型方法引用:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ //compareToIgnoreCase方法是字符串的特定方法,满足特定类型的方法引用。而且是主调,o1.什么, //所以极简版代码:特定类型方法引用:类型名称::方法名 Arrays.sort(names, String::compareToIgnoreCase);javapackage com.itheima.method1reference; import java.util.Arrays; public class Demo3 { public static void main(String[] args) { //目标:特定类型的方法引用 //需求:有一个字符串数组,里面有一些人的名字,请按照名字的首字母升序排序。 String[] names = {"tom" , "Jerry","Caocao","Jack","Rose","Angela","Mike","aplle","Bobi","曹操"}; //把这个数组进行排序,按照首字母。 //把这个数组进行排序:Arrays.sort(names,Comparator); Arrays.sort(names); System.out.println(Arrays.toString(names)); //默认就可以按照首字母排序:A-Z;a-z;0-9 //要求:忽略首字母的大小写进行排序; //Java官方默认是搞不定的,自己制定规则: // Arrays.sort(names, new Comparator<String>() { // @Override // public int compare(String o1, String o2) { // // return o1.compareToIgnoreCase(o2);//Java已经为我们提供了字符串按照首字母忽略大小写比较的方法compareToIgnoreCase; // } // }); //简化: // Arrays.sort(names, (String o1, String o2) -> {return o1.compareToIgnoreCase(o2);}); Arrays.sort(names, (o1,o2)->o1.compareToIgnoreCase(o2)); //compareToIgnoreCase方法是字符串的特定方法,满足特定类型的方法引用。而且是主调,o1.什么, //所以极简版代码:特定类型方法引用:类型名称::方法名 Arrays.sort(names, String::compareToIgnoreCase); System.out.println(Arrays.toString(names)); } }
-
-
构造器引用
------------java基础d8--11---函数式编程-方法引用-构造器引用------------------------------------------------
-
静态方法的引用
-
实例方法的引用
-
特定类型方法的引用
-
构造器引用
- 格式:类名::new
- 使用场景:如果某个Lambda表达式里只是在创建对象,并且"➡"前后参数情况一致,就可以使用构造器引用。
java//假设一个场景:接口的匿名内部类创建一个对象------------------------------------------------------------------------------------------------------------------ CarFactory bc = new CarFactory() { @Override public Car getCar(String name) { return new Car(name);//返回一个汽车对象。 } }; //Lambda表达式简化版: CarFactory fll = name -> new Car(name); //构造器引用: CarFactory bc2 = Car::new;java//脱裤子放屁,专门搞了一个场景使用这个: package com.itheima.method1reference; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; public class Demo4 { public static void main(String[] args) { //目标:理解构造器引用 //因为接口不能有对象,所以创建了一个接口的匿名内部类,充当接口的实现类。 CarFactory bc = new CarFactory() { @Override public Car getCar(String name) { return new Car(name);//返回一个汽车对象。 } }; Car bc1 = new Car("奔驰");//调用匿名内部类的getCar方法。 System.out.println(bc1); //Lambda简化: // CarFactory fll = name -> new Car(name); //构造器引用: CarFactory bc2 = Car::new; Car fll1 = new Car("法拉利"); System.out.println(fll1); } } @FunctionalInterface interface CarFactory{ Car getCar(String name);//先知道,根据名字创建一个对象并返回。 } @Data @AllArgsConstructor @NoArgsConstructor class Car{ private String name; }搞了两个对象,一个叫奔驰一个叫法拉利。
------------java基础d8--12---常用API-String------------------------------------------------------------------------
String是什么?有什么用?
String代表字符串 他的对象可以封装成字符串数据,并提供了很多方法完成对字符串的处理。
- 创建字符串对象,封装字符串数据;
- 调用String提供的操作字符串数据的方法。
创建字符串对象的方式:
-
方法1:Java程序的所有字符串文字都是此类的对象。
- String name = "小黑";
-
方法2:调用String类的构造器初始化字符串对象:
1.|--------------------------------|---------------------|
| 构造器 | 说明 |
| public String() | 创建一个恐怖字符串对象,不含有任何内容 |
| public String(String original) | 根据传入的字符串内容,来创建字符串对象 |
| public String(char[ ] chars) | 根据字符数组的内容,来创建字符串对象 |
| public String(byte[ ] bytes) | 根据字节数组的内容,来创建字符串对象 |阿巴
-
这两种方式的区别:
-
方法1写出的字符串变量,会储存到字符串常量池,且相同内容的字符串只储存一份;
-
方法2即new创建的字符串对象,每new一次都会产生一个新的对象放在堆内存中。
-
底层代码运行方式:
-
代码:
javapublic class Test{ public static void main(String[] ages){ String s1 = "abc"; String s2 = "abc"; System.out.println(a1 == a2); } }1
-
运行:
-
当执行程序的时候,首先把Test类加载到方法区,然后main方法提到栈;
-
执行到第一行,在栈内存开辟一块变量空间,创建一个s1对象,在堆内存的字符串常量池中创建一个"abc",地址返回给s1;
-
执行第二行,在栈内存开辟一块变量空间,创建一个s2对象,在堆内存中发现已经有了"abc",就直接把"abc"的地址返回给s2;
-
第三行问s1和s2的地址是否相等的时候,相等输出ture。
-
-
为什么Java涨么做?
-
节约内存。
-
因为双引号给出的基本都是字面值。
-
且定义也方便。
-
String提供的常用方法:(不需要全部掌握,可以找AI代写)
|---------------------------------------------------------------------|--------------------------------|
| 方法名 | 说明 |
| public int length() | 获取字符串的长度返回(字符个数) |
| public char charAt(int index) | 获取某个索引位置出的字符返回 |
| public char[ ] toCharArray(): | 将当前字符串转换成字符数组返回 |
| public boolean equals(Object anObject) | 判断当前字符串与另一个字符串的内容一样,一样返回ture |
| 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 contains(CharSequence s) | 判断字符串中是否包含了某个字符串 |
| public boolean startsWith(String prefix) | 判断段字符串是否以某个字符串内容开头,开头返回true,反之 |
| public String[ ] split (String regex) | 把字符串按照某个字符串内容分割,并返回字符串数组回来 |
小结:
- String是什么?可以做什么?
- 代表字符串,可以用来创建对象封装字符串数据,并对其进行处理。
- String累创建对象封装字符串数据的方式有几种?
- 方式一:直接使用双引号""
- 方式二:new String类,调用构造器初始化字符串对象。
------------java基础d8--13---常用API-String生成验证码---------------------------------------------------------
需求:实现随机产生验证码,验证码的每位可能是数组、大写字母、小写字母;
java
package com.itheima.Stringdemo2;
import java.util.Scanner;
public class StringDemo2 {
public static void main(String[] args) {
//目标,用String生成随机验证码并返回:每位可能是大写、小写字母或者数字
getCode();
}
public static String getCode(){
String code = "";
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Scanner sc = new Scanner(System.in);
System.out.println("请输入验证码的长度:");
int index = sc.nextInt();
for (int i = 0; i < index; i++) {
int index1 = (int)(Math.random()*str.length());
code += str.charAt(index1);
}
System.out.println(code);
return code;
}
}
实现步骤:
- 定义两个字符串变量,一个code用来记录生成的验证码,一个str用来记住要用到的全部字符;
- 定义for循环控制生成多少位的随机字符,没得到一个字符范围内的随机索引,根据索引提取该字符,吧该字符交给code变量连接起来,循环结束后,在循环外返回code即可。
- 主程序中,调用该方法即可得到随机验证码了。
------------java基础d8--14---常用API-ArrayList集合---------------------------------------------------------------
集合是一种容器,用来装数据的,类似于数组:
- 有数组,为什么还要学习集合?
- 数组定义完成并启动后,长度就固定了;
- 比如创建一个页面,页面用数组的话,就只能有多少个数据,要想加新的数据,只能把前面的数据删掉;
- 用集合的话,就可以无限制往下持续生成新数据。
- 比如要删掉页面的某个数据,那这里就空了,不让他空就得把后边的全都前移一位,特别麻烦。
- 数组定义完成并启动后,长度就固定了;
- 集合是大小可变的,功能更丰富;开发中用的更多。
ArrayList集合学什么?
- 创建ArrayList对象,代表一个集合容器;
- 调用ArrayList提供的方法,对容器中的数据进行增删改查操作。
- 构造器:public ArrayList() 创建一个空的集合对象;
|----------------------------------------|---------------------|
| 常用方法名 | 说明 |
| public boolean add(E e) | 将指定的元素添加到此集合的末尾 |
| public void add(int indedx, E element) | 在此集合中的指定位置插入指定元素 |
| 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) | 修改指定索引处的元素,返回被修改的元素 |
java
package com.itheima.Stringdemo2;
import java.util.ArrayList;
public class ArrayListDemo1 {
public static void main(String[] args) {
//目标:掌握ArrayList集合的基本使用:
//首先我们添加数据
//查看数据。
//删除数据。
//修改数据。
ArrayList list = new ArrayList(); //什么都不加的话,可以添加任意的元素。但是Java是一种强类型语言,不希望我们这样。
list.add("hello");
list.add("world");
list.add(15);
list.add(true);
list.add(0.0354);
System.out.println(list);
ArrayList<String> list1 = new ArrayList(); //带一个泛型,只能操作这种类型。
//1、增加数据:
list1.add("hello");
// list1.add(15);//错误,不能添加非String元素。
list1.add("赵敏");
list1.add("周杰伦");
list1.add("小昭");
list1.add("杨幂");
System.out.println(list1);
//2、查看数据:
System.out.println(list1.get(0));
System.out.println(list1.get(1));
// System.out.println(list1.get(5)); //越界了,没有5这个索引。
//3、删除数据:
list1.remove(0); //根据索引删除
System.out.println(list1.remove("小昭")); //根据元素删除
System.out.println(list1);
//修改数据:
list1.set(0,"小昭"); //根据索引修改
System.out.println(list1);
}
}
小结:
- 集合是什么?有啥特点?
- 一种容器,用来存储数据的
- 集合的大小可变
- ArrayList是什么?怎么使用?
- 是集合中最常用的一种,ArrayList是泛型类,可以约束存储的数据类型;
- 创建对象:调用无参数构造器public ArrayList()初始化对象。
- 调用增删改查的的方法。
------------java基础d8--15---GUI界面编程-快速认识---------------------------------------------------------------
GUI编程是什么?Graphical User Interface 即图形用户界面。
Java的GUI编程效率不高,代码比较臃肿,一般企业开发用其他的语言。
- 通过图像元素(如窗口、按钮、文本框等)与用户进行交互;
- 与命令行界面(CLI)相比,GUI更加直观、友好;
为什么学GUI编程?
- 增强用户体验
- 广泛用于桌面应用程序开发
- java提供了强大的GUI编程支持
Java的GUI编程包:
- AWT(Abstract Window Toolkit)
- 提供了一组原生的GUI组件,依赖于操作系统的本地窗口系统
- Swing
- 基于AWT,提供了更丰富的GUI组件,轻量级组件,不依赖于本地窗口系统。
- 常用的Swing组件
- JFrame:窗口
- JPanel:用于组织其他组件的容器
- JButton:按钮组件
- JTextField:输入框
- JTable:表格
GUI入门:
java
package com.itheima.code.gui;
import javax.swing.*;
public class JFrameDemo1 {
public static void main(String[] args) {
//目标:快速入门一下GUI Swing的编程
//创建一个窗口,有一个输入框,有一个"登录"按钮
// JFrame jf = new JFrame("登录窗口"); //创建窗口
// jf.setSize(400,300); //设置窗口的位置和宽高
// jf.setLocationRelativeTo(null); //设置窗口居中
// jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置关闭窗口的默认操作:关闭窗口退出程序
// JButton btn = new JButton("登录"); //创建一个按钮
// btn.setBounds(100,100,100,50); //设置按钮的位置和宽高
// jf.add(btn);
// jf.setVisible(true); //显示窗口
//这样搞有bug,虽然设置了按钮的大小,但运行的时候还是填充满了整个窗口。
//解决方法用桌布:
JFrame jf = new JFrame("登录窗口");
JPanel panel = new JPanel(); //创建一个桌布
jf.add(panel); //把桌布添加到窗口中
jf.setSize(400,300);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btn = new JButton("登录");
btn.setBounds(100,100,100,50);
panel.add(btn); //把按钮添加到桌布中
jf.setVisible(true);
}
}
常见的布局管理器:
-
布局管理器(Layout Manager)他们可以决定组件在容器中的布局方式避免了手动设置每个组件的位置和大小,从而简化了GUI;
-
常见的布局管理器:
- FlowLayout 水平布局,或者垂直布局
- 按照水平方向从左到右排列组件,当一行排满时,自动换到下一行。
- 默认居中对齐,可以设置左对齐或右对齐
- BorderLayout 按照方向布局;
- 将容器划分为五个区域:东、南、西、北和中(East、South、West、North、Center);每个区域只能添加一个组件,未添加组件的区域保持空白。
- 特点:
- 适用于需要在特定区域布局组件的场景;
- 中间区域会占据所剩余的空间。
- GridLayout1 按照网格布局;
- 将容器划分为等大小的网格,每个网格中可以添加一个组件,所有组件大小相同;
- 特点:
- 适用于需要均匀排列组件的场景;
- 行和列的数量可以指定。
- BoxLayout 也是可以按照方位布局。
- 能够沿着单一轴线(X轴或Y轴)排列组件,可以创建水平或垂直排列的布局;
- 特点:
- 适用于需要沿单一方向排列组件的场景;
- 可以通过添加垂直或水平间隔(Glue、Strut)来调整组件间距;
- FlowLayout 水平布局,或者垂直布局
-
FlowLayout 水平布局,或者垂直布局
1.javapublic static void main(String[] args) { JFrame frame = new JFrame("Flowlayout流式布局"); frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new FlowLayout()); //设置流式布局 frame.add(new JButton("按钮1")); frame.add(new JButton("按钮2")); frame.add(new JButton("按钮3")); frame.add(new JButton("按钮4")); frame.add(new JButton("按钮5")); frame.add(new JButton("按钮6")); frame.setVisible( true); } -
BorderLayout 按照方向布局;
1.javapublic static void main(String[] args) { JFrame frame = new JFrame("BorderLayout流式布局"); frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new java.awt.BorderLayout()); //设置流式布局 frame.add(new JButton("按钮1"), BorderLayout.NORTH); frame.add(new JButton("按钮2"), BorderLayout.SOUTH); frame.add(new JButton("按钮3"), BorderLayout.EAST); frame.add(new JButton("按钮4"), BorderLayout.WEST); frame.add(new JButton("按钮5"), BorderLayout.CENTER); frame.setVisible( true); } -
GridLayout1 按照网格布局;
1.javapublic static void main(String[] args) { JFrame frame = new JFrame("GrdLayout流式布局"); frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new GridLayout(2,3)); //设置流式布局,两行三列 frame.add(new JButton("按钮1")); frame.add(new JButton("按钮2")); frame.add(new JButton("按钮3")); frame.add(new JButton("按钮4")); frame.add(new JButton("按钮5")); frame.add(new JButton("按钮6")); frame.setVisible( true); } -
BoxLayout 也是可以按照方位布局
1.javapublic static void main(String[] args) { JFrame frame = new JFrame("BoxLayout流式布局"); frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); //配合桌布使用。所有的流式布局都可以配合桌布使用。 panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS)); //设置流式布局,Y_AXIS是Y轴的 panel.add(new JButton("按钮1")); panel.add(Box.createVerticalStrut(10)); //添加两个按钮之间的垂直间距。 panel.add(new JButton("按钮2")); panel.add(Box.createVerticalStrut(10)); panel.add(new JButton("按钮3")); panel.add(Box.createVerticalStrut(10)); panel.add(new JButton("按钮4")); frame.add(panel); frame.setVisible(true); }
------------java基础d8--16---GUI界面编程-事件处理---------------------------------------------------------------
事件处理:
- 什么是事件:
- 比如按键,用户的所有操作都是事件。
- GUI编程中,事件的处理是通过事件监听器(Event Listener)来完成的。
- 常用的事件监听器对象:
- 点击事件监听器ActionListener
- 按键事件监听器KeyListener
- 鼠标行为监听器MouseListener
- 常用的事件监听器对象:
------------java基础d8--17---GUI界面编程-事件的写法------------------------------------------------------------
常见事件写法:
-
直接提供实现类,用于创建事件监听对象;
java//最下边写的就是实现类。------------------------------------------------------------------------------------------------------------------------------ package com.itheima.gui2; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Test2 { public static void main(String[] args) { //目标:第一种写法,提供实现类,创建是实现类对象代表事件监听器 JFrame jf = new JFrame("登录窗口"); JPanel panel = new JPanel(); jf.add(panel); jf.setSize(400,300); jf.setLocationRelativeTo(null); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton btn = new JButton("登录"); btn.setBounds(100,100,100,50); panel.add(btn); btn.addActionListener(new MyActionListener(jf)); //把手动写的事件添加进来。 jf.setVisible(true); } } class MyActionListener implements ActionListener { private JFrame jf; //窗口送过来需要一个变量来接收,就定义一个。 public MyActionListener(JFrame jf){ this.jf = jf; } @Override public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(jf,"点击了登录按钮"); //因为弹窗需要依赖于窗口,所以需要把窗口送下来,传递给这个方法。 } } -
直接使用匿名内部类的对象,代表事件监听对象;
javajb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //(这个是可以简化的哟) //一旦点击按钮,就会执行这个方法 //这个参数e是一个事件对象,里面封装了事件相关的信息。 // e.setSource(jb);//得到了点击事件的按钮 // System.out.println("点击了登录按钮"); JOptionPane.showMessageDialog(jf,"登录成功!"); //弹出一个对话框 } }); //以上就是使用匿名内部类搞的事件监听器,以下是全代码: package com.itheima.gui2; 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的事件处理机制: JFrame jf = new JFrame("登录窗口"); JPanel panel = new JPanel(); jf.add(panel); jf.setSize(400,300); jf.setLocationRelativeTo(null); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JButton jb = new JButton("登录"); panel.add(jb); //给按钮添加一个事件监听器 jb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { //(这个是可以简化的哟) //一旦点击按钮,就会执行这个方法 //这个参数e是一个事件对象,里面封装了事件相关的信息。 // e.setSource(jb);//得到了点击事件的按钮 // System.out.println("点击了登录按钮"); JOptionPane.showMessageDialog(jf,"登录成功!"); //弹出一个对话框 } }); //需求:监听用户键盘上下左右四个按键的事件。 //给jf窗口整体绑定按键事件。 jf.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { //e表示按的是哪个按键。 System.out.println("按下了某个按键"); //只要按下就会触发。 //一旦按下按键,就会执行这个方法 //这个参数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窗口,也就是说现在没办法把按键直接传给窗口。 jf.setVisible(true); //显示完窗口要让窗口成为焦点,获取按键的焦点 jf.requestFocus();//让窗口接收按键。 //问题:鼠标按下登录按钮之后有个新弹窗,然后窗口就又不是焦点了。 } } -
自定义窗口,让窗口对象实现事件接口。
java//首先是一个类,继承JFrame,让他更方便的写GUI;然后继承事件监听器接口; package com.itheima.gui2; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class LoginFrame extends JFrame implements ActionListener { //想自定义一个窗口,那要继承JFrame类 //直接继承那个接口,让整个窗口成为事件监听器 public LoginFrame(){ this.setTitle("登录窗口"); this.setSize(400,300); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); init(); //初始化这个窗口的组件; } private void init(){ //添加一个登录按钮 JButton jb = new JButton("登录"); jb.addActionListener(this); //现在this就是窗口对象了,所以可以这样写。 //搞一个桌布; JPanel panel = new JPanel(); this.add(panel); panel.add(jb); //在桌布上添加这个按钮; } @Override public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(this,"登录成功!"); } } //以下是main方法------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ package com.itheima.gui2; public class Test3 { public static void main(String[] args) { //目标:自定义一个登录界面,让界面对象本身也是事件监听器对象。 // JFrame jf = new JFrame("登录窗口"); // LoginFrame lf = new LoginFrame(); //那以后这样搞一个窗口就好了呀。 lf.setVisible(true); } }