Java-进阶篇【面向对象进阶,static、单例、代码块、继承、权限修饰符、抽象类、接口】---04

1:PIC内容

 2:static 关键字 修饰成员变量  【静态成员变量  静态成员方法】

static 是静态的意思,可以用来修饰 成员变量、成员方法。
static 修饰成员变量 之后称为静态成员变量(类变量),修饰方法之后称为静态方法(类方法)。【表示该成员变量在内存中只存在一份,可以被共享访问修改】
     静态成员变量(有static 修饰,属于类,内存中加载一次)(如表示在线人数,需要被共享的信息,可以被共享访问)
static 修饰后的成员变量,可以被类的所有对象共享(访问、修改)
public class User     
    static String name;
    int age;
}
类名.静态成员变量   (推荐这样直接访问)
对象.静态成员变量  (也可以这样访问,但是不推荐)

成员变量【无 static 修饰,存在于每个对象中】,比如常用的 name,age 等都是属于每个对象的信息 【实例成员变量】
package com.itheima.d1_static;

public class User {
    /**
      在线人数。
      注意:static修饰的成员变量:静态成员变量,只在内存中有一份,可以被共享【不会放在对象中】
     */
    public static int onlineNumber = 161;
    
    /**
       实例成员变量:无static修饰,属于每个对象的,必须用对象名.访问
     */
    private String name;
    private int age;

    public static void main(String[] args) {
        // 目标:理解static修饰成员变量的作用和访问特点。
        // 1、类名.静态成员变量。
        System.out.println(User.onlineNumber);

        // 2、对象名.实例成员变量
        // System.out.println(User.name); // 报错
        User u = new User();
        u.name = "张三";
        u.age = 21;
        System.out.println(u.name);
        System.out.println(u.age);
        u.onlineNumber++; // 新来了一个人
        System.out.println(u.onlineNumber);

        User u2 = new User();
        u2.name = "张三2";
        u2.age = 22;
        System.out.println(u2.name);
        System.out.println(u2.age);
        u2.onlineNumber++; // 新来了一个人

        System.out.println(u.onlineNumber);
        System.out.println(User.onlineNumber); // 推荐方式
        // 注意:同一个类中静态成员变量的访问可以省略类名。【其他类中访问需要加上类名】
        System.out.println(onlineNumber);
    }
}
static修饰的成员变量内存机制

 3:static 关键字 修饰成员方法  【静态成员变量  静态成员方法】

成员方法的分类:
    静态成员方法(有static修饰,归属于类),建议用类名访问,也可以用对象访问。
    实例成员方法(无static修饰,归属于对象),只能用对象触发访问

表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法。
如果该方法是以执行一个共用功能为目的,则可以申明成静态方法  

package com.itheima.d1_static;

public class Student {
    private String name;        // 实例成员变量:无static修饰,属于对象。

    public static int getMax(int age1, int age2){  // 静态成员方法: 有static修饰,归属于类,可以被共享访问,用类名或者对象名都可以访问。
        return age1 > age2 ? age1 : age2;
    }

    public void study(){    // 例方法:属于对象的,只能用对象触发访问
        System.out.println(name + "在好好学习,天天向上~");
    }
    public static void main(String[] args) {
        // 1、类名.静态成员方法
        System.out.println(Student.getMax(10, 3));
        // 注意:同一个类中,访问静态方法,类名可以省略不写。
        System.out.println(getMax(10, 32));
//         study(); // 报错了      属于对象的,只能对象访问
        // 2、对象.实例方法
        Student s = new Student();
        s.name = "猪八戒";
        s.study();
        // 3、对象.静态方法 (语法是可行,但是不推荐)
        System.out.println(s.getMax(13,34));
    }
}

 4:static 修饰成员方法的内存原理

5:static 注意事项

static访问注意事项:
  静态方法只能访问静态的成员,不可以直接访问实例成员。【静态成员属于类,可以共享,实例成员属于对象,对象触发】
  实例方法可以访问静态的成员,也可以访问实例成员。【静态成员共享的】
  静态方法中是不可以出现this关键字的 【this代表当前对象,静态方法可能不是对象调用的,所以不能出现this】
package com.itheima.d1_static;

public class Test3 {
    /**
       静态成员
     */
    public static int onlineNumber = 10;
    public static void test2(){
        System.out.println("==test2==");
    }
    /**
      实例成员
     */
    private String name;
    public void run(){
        System.out.println(name + "跑的快~~");
    }

    // 3、静态方法中不可以出现this关键字
    public static void test3(){
        // System.out.println(this); // this只能代表当前对象!!
    }
    // 2、实例方法可以访问静态成员,也可以访问实例成员
    public void go(){
        System.out.println(Test3.onlineNumber);
        System.out.println(onlineNumber);
        test2();
        System.out.println(name);
        System.out.println(this);
        run();
    }
    // 1、静态方法只能访问静态成员,不能"直接"访问实例成员。
    public static void test(){
        System.out.println(Test3.onlineNumber);
        System.out.println(onlineNumber);
        test2();
    }
    public static void main(String[] args) {
        // 目标:理解static 访问相关的语法:面试笔试题,或者以后理解程序很重要的知识(拓展)。
    }
}

 6:static 工具类    

工具类是什么?
  类中都是一些静态方法,每个方法都是以完成一个共用的功能为目的,这个类用来给系统开发人员共同使用的。

案例导学:
  在企业的管理系统中,通常需要在一个系统的很多业务处使用 验证码 进行防刷新等安全控制

问题:
  同一个功能多处开发,会出现代码重复度过高

使用工具类的好处
  一是调用方便,二是提高了代码复用(一次编写,处处可用)
package com.itheima.d2_static_util;

import java.util.Random;
/**
   工具类
 */
public class ItheimUtil {
    /**
       注意:由于工具类无需创建对象,所以把其构造器私有化会显得很专业!
     */
    private ItheimUtil(){
    }

    /**
       静态方法。
     */
    public static String createVerifyCode(int n){
        // 开发一个验证码:
        // 1、定义一个变量记住验证码。
        String code = "";
        // 2、定义一个变量记住全部验证码字符。
        String data = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        // 3、定义一个循环生成几个随机索引,去得到几个字符
        Random r = new Random();
        for (int i = 0; i < n; i++) {
            // 4、获取随机索引对应的字符。链接给code
            int index = r.nextInt(data.length());
            code += data.charAt(index);
        }
        return code;
    }
    public static void main(String[] args) {
        System.out.println(ItheimUtil.createVerifyCode(10));
    }
}
为什么工具类中的方法不用实例方法做? 
  实例方法需要创建对象调用。
  此时用对象只是为了调用方法,这样只会浪费内存。

工具类定义时的其他要求:
  由于工具里面都是静态方法,直接用类名即可访问,因此,工具类无需创建对象,建议将工具类的构造器进行私有  
  private ItheimUtil
定义数组工具类
需求:在实际开发中,经常会遇到一些数组使用的工具类。请按照如下要求编写一个数组的工具类:ArraysUtils
  1:我们知道数组对象直接输出的时候是输出对象的地址的,而项目中很多地方都需要返回数组的内容,
    请在ArraysUtils中提供一个工具类方法toString,用于返回整数数组的内容,
    返回的字符串格式如:[
10, 20, 50, 34, 100](只考虑整数数组,且只考虑一维数组)   2:经常需要统计平均值,平均值为去掉最低分和最高分后的分值,请提供这样一个工具方法getAerage,用于返回平均分。
    (只考虑浮点型数组,且只考虑一维数组)   3:定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果
package com.itheima.d2_static_util;

public class ArrayUtil {
    private ArrayUtil(){    // 构造器私有化
    }
    // 工具方法
    public static String toSting(int[] arr){
        if (arr == null) {
            return null;
        }
        // 拼接内容返回
        String result = "[";
        for (int i = 0; i < arr.length; i++) {
            result += (i == arr.length-1 ? arr[i]: arr[i] + ", ");
        }
        result += "]";
        return result;
    }
    public static void main(String[] args) {
        int[] array1 = {1, 2, 3, 4};
        System.out.println(ArrayUtil.toSting(array1));
        int[] array2 = {};
        System.out.println(ArrayUtil.toSting(array2));
        int[] array3 = null;
        System.out.println(ArrayUtil.toSting(array3));
    }
}

 7:static 代码块    初始化数据

代码块概述
  代码块是类的5大成分之一(成员变量、构造器,方法,代码块,内部类),定义在类中方法外。
  在Java类下,使用 { } 括起来的代码被称为代码块 。

代码块分为
  静态代码块: 属于类
  格式:static{}
  特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次
  使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用

构造代码块(了解,见的少):
  格式:{}
  特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行
  使用场景:初始化实例资源
package com.itheima.d3_static_code;

public class StaticDemo1 {

    public static String schoolName;
    /**
       静态代码块:有static修饰,属于类,与类一起优先加载一次,自动触发执行。
       作用:可以用于初始化静态资源。
        跟类一起加载,执行在 mian 方法之前
     */
    static {
        System.out.println("------静态代码块被触发执行了------");
        schoolName = "黑马";
    }
    public static void main(String[] args) {
        // 目标:先理解静态代码块。
        System.out.println("------main方法执行------");
        System.out.println(schoolName);
    }
}
package com.itheima.d3_static_code;

public class StaticDemo2 {
    private String name;
    public StaticDemo2(){
        System.out.println("===无参构造器被触发执行==");
    }
    /**
       实例代码块【构造代码块】:无static修饰,属于对象,每次构建对象时,都会触发一次执行。
       初始化实例资源。
     */
    {
        //name = "张三";
        System.out.println("===实例代码块被触发执行===");
    }
    public static void main(String[] args) {
        // 目标:理解实例代码块(构造代码块)。
        StaticDemo2 s1 = new StaticDemo2();
        System.out.println(s1.name);

        StaticDemo2 s2 = new StaticDemo2();
        System.out.println(s2.name);
    }
}
在启动游戏房间的时候,应该提前准备好54张牌,后续才可以直接使用这些牌数据
  该房间只需要一副牌。
  定义一个静态的ArrayList集合存储54张牌对象,静态的集合只会加载一份。
  在启动游戏房间前,应该将54张牌初始化好
  当系统启动的同时需要准备好54张牌数据,此时可以用静态代码块完成
package com.itheima.d3_static_code;
import java.util.ArrayList;
public class StaticTest3 {

    /**
      1、定义一个静态的集合,这样这个集合只加载 一个。因为当前房间只需要一副牌。
     */
    public static ArrayList<String> cards = new ArrayList<>();

    /**
      2、在程序真正运行main方法前,把54张牌放进去吧,后续游戏可以直接使用了。
     */
    static {
        // 3、正式做牌,放到集合中去。
        // a、定义一个数组存储全部点数:类型确定了,个数确定了。
        String[] sizes = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
        // b、定义一个数组存储全部的花色:类型确定了,个数确定了。
        String[] colors = {"♥", "♠", "♦", "♣"};
        // c、遍历点数
        for (int i = 0; i < sizes.length; i++) {
            // sizes[i]
            // d、遍历花色
            for (int j = 0; j < colors.length; j++) {
                // colors[j]
                // 一张牌
                String card = sizes[i] + colors[j];
                cards.add(card);
            }
        }
        // e、单独加入大小王。
        cards.add("小🃏");
        cards.add("大🃏");
    }
    public static void main(String[] args) {
        // 目标:模拟游戏启动前,初始化54张牌数据。
        System.out.println("新牌:" + cards);
    }
}

8:static 单例设计模式

什么是设计模式(Design pattern)
  开发中经常遇到一些问题,一个问题通常有n种解法的,但其中肯定有一种解法是最优的,这个最优的解法被人总结出来了,称之为设计模式。
  设计模式有20多种,对应20多种软件开发中会遇到的问题。
  学设计模式主要是学2点:
    第一:这种模式用来解决什么问题。
    第二:遇到这种问题了,该模式是怎么写的,他是如何解决这个问题的
单例模式
  可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象。
  例如任务管理器对象我们只需要一个就可以解决问题了,这样可以节省内存空间

单例的实现方式很多
  饿汉单例模式。
  懒汉单例模式。
饿汉单例设计模式
  在用类获取对象的时候,对象已经提前为你创建好了

设计步骤:
  定义一个类,把构造器私有。
  定义一个静态变量存储一个对象
public class SingleInstance 
    /** c.定义一个静态变量存储一个对象即可 :属于类,与类一起加载一次 *
    public static SingleInstance instance = new SingleInstance ();
    /** b.单例必须私有构造器*    
    private SingleInstance ()        
      System.out.println("创建了一个对象")
    }
}    
package com.itheima.d4_static_singleinstance;

/**
   使用饿汉单例实现单例类
 */
public class SingleInstance {

    /**
      2、饿汉单例是在获取对象前,对象已经提前准备好了一个。
       这个对象只能是一个,所以定义静态成员变量记住。
     */
    public static SingleInstance instance = new SingleInstance();

    /**
       1、必须把构造器私有化。
     */
    private SingleInstance(){
    }

    public static void main(String[] args) {
        SingleInstance s1 = SingleInstance.instance;
        SingleInstance s2 = SingleInstance.instance;
        System.out.println(s1 == s2);
    }
}
懒汉单例设计模式
    在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。

设计步骤:
    定义一个类,把构造器私有。
    定义一个静态变量存储一个对象。
    提供一个返回单例对象的方法
package com.itheima.d4_static_singleinstance;
/**
   懒汉单例
 */
public class SingleInstance2 {
    /**
      2、定义一个静态的成员变量负责存储一个对象。
         只加载一次,只有一份。
       注意:最好私有化,这样可以避免给别人挖坑!
     */
    private static SingleInstance2 instance;

    /**
      3、提供一个方法,对外返回单例对象。
     */
    public static SingleInstance2 getInstance() {
        if(instance == null){
            // 第一次来拿对象 :此时需要创建对象。
            instance = new SingleInstance2();
        }
        return instance;
    }
    
    /**
       1、私有化构造器
     */
    private SingleInstance2(){
    }

    public static void main(String[] args) {
        // 目标: 掌握懒汉单例的设计。理解其思想。
        SingleInstance2 s1 = SingleInstance2.getInstance();
        SingleInstance2 s2 = SingleInstance2.getInstance();
        System.out.println(s1 == s2);
    }
}

9:继承    extends  关键字

什么是继承?
  Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起父子关系。
    public class Student extends People {}
  Student称为子类(派生类),People称为父类(基类 或超类)。
  作用:当子类继承父类后,就可以直接使用父类公共的属性和方法了

使用继承的好处
  可以提高代码的复用性

10:继承的 内存运行原理

继承设计规范:
  子类们相同特征(共性属性,共性方法)放在父类中定义,子类独有的的属性和行为应该定义在子类自己里面

为什么? 
  如果子类的独有属性、行为定义在父类中,会导致其它子类也会得到这些属性和行为,这不符合面向对象逻辑。

如下:对外一个子类对象,但是分成两个空间,子类空间和父类空间【对外一个对象】

11:继承的特点

继承的特点
  子类可以继承父类的属性和行为,但是 子类不能继承父类的构造器。
  Java是单继承模式:一个类只能继承一个直接父类。
  Java不支持多继承、但是支持多层继承。【多个父类有多个相同方法,调用的使用不知道使用那个父类的方法,跟python不同】
  Java中所有的类都是Object类的子类。
子类是否可以继承父类的构造器?
  不可以的,子类有自己的构造器,父类构造器用于初始化父类对象

子类是否可以继承父类的私有成员?
  可以的,只是不能直接访问

子类是否可以继承父类的静态成员
  子类可以直接使用父类的静态成员(共享)
  个人认为:子类不能继承父类的静态成员(共享并非继承)

package com.itheima.d7_extends_feature;

public class Test {
    public static void main(String[] args) {
        // 目标:理解继承的特点。
        // 1、子类不能继承父类的构造器
        // 2、子类是否可以继承父类的私有成员? 我认为是可以继承父类私有成员的,只是不能直接访问。
        Tiger t = new Tiger();
        // t.eat();
        // 3、子类是否可以继承父类的静态成员。 我认识不算继承的。只是共享的。
        System.out.println(Tiger.location);
    }
}
class Animal{ private void eat(){ System.out.println("动物要吃东西~~"); } public static String location = "长隆动物园"; }
class Tiger extends Animal{ }

12:继承之  成员变量,成员方法的访问

在子类方法中访问成员(成员变量、成员方法)满足:就近原则
  先子类局部范围找
  然后子类成员范围找
  然后父类成员范围找,如果父类范围还没有找到则报错

如果子父类中,出现了重名的成员,会优先使用子类的,此时如果一定要在子类中使用父类的怎么办?
  可以通过super关键字,指定访问父类的成员。
  格式:super.父类成员变量/父类成员方法
  this super 的使用
package com.itheima.d8_extends_field_method;

public class Test {
    public static void main(String[] args) {
        // 目标:理解继承后成员的访问特点:就近原则。
        Dog d = new Dog();
        d.run(); // 子类的
        d.lookDoor(); // 子类的
        d.showName();
    }
}

class Animal{
    public String name = "动物名";
    public void run(){
        System.out.println("动物可以跑~~");
    }
}

class Dog extends Animal{
    public String name = "狗名";

    public void lookDoor(){
        System.out.println("狗可以看门~~");
    }

    public void showName(){
        String name = "局部名";
        System.out.println(name);
        System.out.println(this.name); // 当前子类对象的name
        System.out.println(super.name); // 找父类的name

        super.run(); // 找父类的方法
        run(); // 子类的run
    }

    public void run(){
        System.out.println("狗跑的贼快~~~");
    }
}

 13:继承之  方法重写  @overdide

什么是方法重写?
  在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
方法重写的应用场景
  当子类需要父类的功能,但父类的该功能不完全满足自己的需求时。
  子类可以重写父类中的方法。
案例演示:
  旧手机的功能只能是基本的打电话,发信息
  新手机的功能需要能够:基本的打电话下支持视频通话。基本的发信息下支持发送语音和图片
@Override重写注解
  @Override是放在重写后的方法上,作为重写是否正确的校验注解。
  加上该注解后如果重写错误,编译阶段会出现错误提示。
  建议重写方法都加@Override注解,代码安全,优雅!

方法重写注意事项和要求
  重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致。
  私有方法不能被重写。  父类 privite 修饰的
  子类重写父类方法时,访问权限必须大于或者等于父类 (暂时了解 :缺省 < protected < public)  【一般访问权限和父类保持一致】
    私有权限:最小privite【本类】  缺省:在本类和本包下面访问  protected:本类,本包,其他类,其他包的子类中可以访问   public:    子类不能重写父类的静态方法,如果重写会报错的。【静态方法属于父类本身,父类的静态方法父类的类名调用,子类的静态方法子类的类名调用】
package com.itheima.d9_extends_override;

public class Test {
    public static void main(String[] args) {
        // 目标:认识方法重写。
        NewPhone hw = new NewPhone();
        hw.call();
        hw.sendMsg();
    }
}

/**
   新手机:子类。
 */
class NewPhone extends Phone{
    // 重写的方法
    // 1、@Override重写校验注解,加上之后,这个方法必须是正确重写的,这样更安全。2、提高程序的可读性,代码优雅!
    // 注意:重写方法的名称和形参列表必须与被重写的方法一模一样。
    @Override
    public void call(){
        super.call(); // 先用它爸爸的基本功能
        System.out.println("开始视频通话~~");
    }
    // 重写的方法
    @Override
    public void sendMsg(){
        super.sendMsg(); // 先用它爸爸的基本功能
        System.out.println("发送有趣的图片~");
    }

    // 注意:静态方法不能被重写。
//    @Override
//    public static void test(){
//
//    }
}

/**
   旧手机:父类的
 */
class Phone{
    public void call(){
        System.out.println("打电话~");
    }

    public void sendMsg(){
        System.out.println("发短信~");
    }

    public static void test(){
    }
}

 13:继承之  子类构造器特点

子类继承父类后构造器的特点:
  子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己。

为什么?
  子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
  子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化。

怎么调用父类构造器的?
  子类构造器的第一行语句默认都是:super(),不写也存在
package com.itheima.d10_extends_constructor;

public class Test {
    public static void main(String[] args) {
        // 目标:认识继承后子类构造器的特点
        // 特点:子类的全部构造器默认会先访问父类的无参数构造器再执行自己
        Dog d1 = new Dog();
        System.out.println(d1);
        System.out.println("-----");
        Dog d2 = new Dog("金毛");
        System.out.println(d2);
    }
}

class Dog extends Animal{
    public Dog(){
//        super(); // 写不写都有,默认找父类的无参数构造器执行
        System.out.println("子类Dog无参数构造器被执行~");
    }

    public Dog(String name){
//        super(); // 写不写都有,默认找父类的无参数构造器执行
        System.out.println("子类Dog有参数构造器被执行~");
    }
}

class Animal {
    public Animal(){
        System.out.println("父类Animal无参数构造器被执行~");
    }
}

14:继承之  子类构造器访问父类的有参构造器

super调用父类有参数构造器的作用:
  初始化继承自父类的数据。

如果父类中没有无参数构造器,只有有参构造器,会出现什么现象呢?
  会报错。因为子类默认是调用父类无参构造器的。

如何解决?
  子类构造器中可以通过书写 super(…),手动调用父类的有参数构造器

super调用父类有参数构造器的作用
  初始化继承自父类的数据【通过调用父类的有参数构造器来初始化继承来自父类的数据】

如果父类中没有无参数构造器,只有有参数构造器,会出现什么情况
  报错,因为子类中默认的构造器都会调用父类的无参数构造器
  子类可以通过 super() 手动调用父类的各种构造器,有参,无参的都可以 【父类的有参,无参构造器都要提供】
package com.itheima.d11_extends_constructor;

public class Test {
    public static void main(String[] args) {
        // 目标:学习子类构造器如何去访问父类有参数构造器,还要清楚其作用。
        Teacher t = new Teacher("dlei", 18);
        System.out.println(t.getName());
        System.out.println(t.getAge());
    }
}

class People {
    private String name;
    private int age;

    public People(){
    }

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

class Teacher extends People{

    public Teacher(){
    }

    public Teacher(String name, int age){
        super(name, age);       // 调用父类的有参数构造器:初始化继承自父类的数据
        // 不能使用 this.name 赋值,因为name不在子类空间,在父类空间,需要使用super

//        super.setName(name);  // 这样也能初始化数据
//        super.setAge(age);
    }
}

 15:this + super 关键字使用

package com.itheima.d12_this;

public class Test {
    public static void main(String[] args) {
        // 目标:理解this(...)的作用:本类构造器中访问本类兄弟构造器。
        Student s1 = new Student("殷素素", "冰火岛自学");
        System.out.println(s1.getName());
        System.out.println(s1.getSchoolName());

        /**
        如果学生不填写学校,默认这个对象的学校是黑马
        */
        Student s2 = new Student("张三丰");
        System.out.println(s2.getName());
        System.out.println(s2.getSchoolName());
    }
}

class Student {
    private String name;
    private String schoolName;
    public Student() {
    }

    public Student(String name) {   // 如果学生不填写学校,默认这个对象的学校是黑马 [只接名称]
        this(name, "灰度程序员");    // 借用本类兄弟构造器
    }

    public Student(String name, String schoolName) {
        // super(); // 必须先初始化父类,再初始化自己。
        this.name = name;
        this.schoolName = schoolName;
    }

    public String getName() {
        return name;
    }

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

    public String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }
}
this(...)和super(…)使用注意点:
  子类通过 this (...)去调用本类的其他构造器,本类其他构造器会通过 super 去手动调用父类的构造器,最终还是会调用父类构造器的。
  注意:this(…) super(…) 都只能放在构造器的第一行,所以二者不能共存在同一个构造器中。

  16:包  和   导包  包的声明

什么是包?
  包是用来分门别类的管理各种不同类的,类似于文件夹、建包利于程序的管理和维护。
  建包的语法格式:package 公司域名倒写.技术名称。报名建议全部英文小写,且具备意义

package com.itheima.javabean;
public class Student {
       }

建包语句必须在第一行,一般IDEA工具会帮助创建

导包  
  相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!导包格式:import 包名.类名;
  假如一个类中需要用到不同类,而这个两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。

alt + 回车 快捷导包
idea 可以配置自动导包
工程结构

 com.itheima.di_package.it.Student.class
package com.itheima.d1_package.it;
public class Student {
}

 com.itheima.di_package.it2.Student.class

package com.itheima.d1_package.it2;
public class Student {
}

 com.itheima.di_package.User.class

package com.itheima.d1_package;

public class User {
    public static int onlineNumber = 121;
}

 com.itheima.di_package.Test.class

package com.itheima.d1_package;

// 导包。
import com.itheima.d1_package.it.Student;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        // 目标:理解以下两点
        // 1、同一个包下的类,互相可以直接访问。
        System.out.println(User.onlineNumber);

        // 2、不同包下的类,必须先导包才可以访问。
        Student s = new Student();
        Scanner sc = new Scanner(System.in);

        // 3、如果这个类中使用不同包下的相同的类名,
        // 此时默认只能导入一个类的包,另一个类要使用全名访问。
        com.itheima.d1_package.it2.Student s2 = new com.itheima.d1_package.it2.Student();
    }
}

17:权限修饰符    private【私有】 -> 缺省【默认,包访问权限】 -> protected【子类访问权限】 - > public 【】

什么是权限修饰符?
  权限修饰符:是用来控制一个成员能够被访问的范围。
  可以修饰 成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能够被访问的范围将受到限制

权限修饰符的分类和具体作用范围:
  权限修饰符:有四种作用范围由小到大(private -> 缺省 -> protected - > public

工程目录

 com.itheima.d2_modifier.itcast.Tes2.class
package com.itheima.d2_modifier.itcast;

import com.itheima.d2_modifier.Fu;

public class Tes2 {
    public static void main(String[] args) {  // 其他包下的无关类 中 只能 访问 public
        Fu f = new Fu();
        //f.privateMethod(); // 报错
        //f.method();// 报错
        //f.protectedMethod();// 报错
        f.publicMethod();
    }
}

 com.itheima.d2_modifier.itcast.Zi.class

package com.itheima.d2_modifier.itcast;

import com.itheima.d2_modifier.Fu;

public class Zi extends Fu {
    public static void main(String[] args) { // 其他包下的子类,只能访问 pubulic 和 protected 【子类对象才可以访问,父类对象不能访问】
        Zi zi = new Zi();
        zi.protectedMethod();
        zi.publicMethod();

        Fu f = new Fu();
        f.publicMethod();
    }
}

 com.itheima.d2_modifier.Fu.class

package com.itheima.d2_modifier;

public class Fu {
    /**
       1、定义私有的成员:  private 只能本类中访问。
     */
    private void privateMethod(){
        System.out.println("---private--");
    }

    /**
     2、定义缺省修饰的成员:  只能本类中、同包下其他类访问(包访问权限)
     */
    void method(){
        System.out.println("---缺省--");
    }

    /**
     3、protected修饰的方法:本类,同包的其他类中,其他包的子类中。
     */
    protected void protectedMethod(){
        System.out.println("---protected--");
    }

    /**
     4、public修饰的方法:本类,同包的其他类中,其他包的子类中,其他包的无关类中。
     */
    public void publicMethod(){
        System.out.println("---public--");
    }

    public static void main(String[] args) {  // 本类中的,4种权限都能访问
        Fu f = new Fu();
        f.privateMethod();
        f.method();
        f.protectedMethod();
        f.publicMethod();
    }
}

 com.itheima.d2_modifier.Test.class

package com.itheima.d2_modifier;

public class Test {
    public static void main(String[] args) {
        // 目标:讲解权限修饰符的修饰范围。明白每一种修饰后的作用范围。
        Fu f = new Fu();
        // f.privateMethod(); // 报错的,私有的  同包下的,私有不能访问
        f.method();
        f.protectedMethod();
        f.publicMethod();
    }
}
能够识别别人定义的成员的访问范围。
自己定义成员(方法,成员变量,构造器等)一般需要满足如下要求:
  成员变量一般私有。  privite
  方法一般公开。  public
  如果该成员只希望本类访问,使用private修饰。
  如果该成员只希望本类,同一个包下的其他类和子类访问,使用protected修饰。

18:final 修饰符

final的作用
  final 关键字是最终的意思,可以修饰(类、方法、变量)
  修饰类:表明该类是最终类,不能被继承。
  修饰方法:表明该方法是最终方法,不能被重写。
  修饰变量:表示该变量第一次赋值后,不能再次被赋值(有且仅能被赋值一次)

final修饰变量的注意
  final修饰的变量是基本类型:那么变量存储的数据值不能发生改变。
  final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,但是地址指向的对象内容是可以发生变化的
package com.itheima.d3_final;

public class Test {
    public static void main(String[] args) {
        // 目标:记住final的语法。
        // 1、final修饰类,类不能被继承。
        // 2、final修饰方法,方法不能被重写
        // 3、final修饰变量,总规则:变量有且仅能被赋值一次。
    }
}

class Student extends People{
//    @Override
//    public void eat() {   // 2、final修饰方法,方法不能被重写
//        System.out.println("学生吃的很多~~");
//    }
}

class People{
    public final void eat(){
        System.out.println("人都要吃东西~~");
    }
}


//class Wolf extends Animal{        // 1、final修饰类,类不能被继承。[工具类使用 final 修饰]
//}

//final class Animal{
//}
package com.itheima.d3_final;

public class Test2 {

    /**
        二:修饰静态成员变量(public static final修饰的也称为常量了),final定义的时候就要赋值,不然报错
     */
    public static final String schoolName = "黑马";

    /**
       三,修饰实例成员变量。(几乎不用)    final定义的时候就要赋值,不然报错
     */
    private final String name = "猪刚鬣";

    public static void main(String[] args) {
        // 目标:理解final修饰变量的作用:总规则:变量有且仅能被赋值一次。(理解语法)
        // 变量有几种:
        //    1、局部变量
        //    2、成员变量
        //           -- 实例成员变量。
        //           -- 静态成员变量。

        // 一:修饰局部变量【修饰局部变量的一种】
        final double rate = 3.14;
        // rate = 3.19; // 第二次赋值了会报错。
        buy(0.8);

        // schoolName = "黑马程序员"; // 第二次赋值了。

        Test2 t = new Test2();
        System.out.println(t.name);
        // t.name = "天蓬元帅";

        // 注意:final修饰引用类型的变量,其地址值不能改变,但是指向的对象的内容可以改变的。
        final Teacher t2 = new Teacher("学习,授课,吹吹水~~");
        // t2 = null;  // 第二次赋值了。
        System.out.println(t2.getHobby());
        t2.setHobby("运动");
        System.out.println(t2.getHobby());
    }

    public static void buy(final double z){ // 二:修饰传参【修饰局部变量的一种】
         // z = 0.1; // z不能第二次赋值了。,接收的时候就已经赋值一次了
    }
}

class Teacher{
    private String hobby;

    public Teacher(String hobby) {
        this.hobby = hobby;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

19:常量

常量 
  常量是使用了 public static final 修饰的成员变量,必须有初始化值,而且执行的过程中其值不能被改变。
  常量名的命名规范:英文单词全部大写,多个单词下划线连接起来。
  常量的作用:通常用来记录系统的配置数据。

public class Constant {
    public static final String SCHOOL_NAME  = “传智教育";
    public static final String LOGIN_NAME  = “admin";
    public static final String PASS_WORD  = “123456";
} 

常量做信息配置的原理、优势
  在编译阶段会进行“宏替换”:把使用常量的地方全部替换成真实的字面量。
  维护系统容易,可读性更好
案例说明:
  现在开发的超级玛丽游戏需要接收用户输入的四个方向的信号(上下左右),以便控制玛丽移动的方向。

选择常量做信息标志和分类:【如下案例】
  代码可读性好,实现了软编码形式
public class Constant {    // 常量
    public static final int UP = 1;
    public static final int DOWN = 2;
    public static final int LEFT = 3;
    public static final int RIGHT = 4;
}
package com.itheima.d4_constant;

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

public class Test2 {
    public static void main(String[] args) {
        // 目标:理解常量的另外一个作用:做信息的标志和分类。
        // 模拟:控制玛丽的移动:上下左右。
        // 桌面编程
        // 1、创建窗口
        JFrame win = new JFrame("超级玛丽");
        win.setSize(300, 200);

        // 2、设计一个面板(桌布)
        JPanel jPanel = new JPanel();
        win.add(jPanel);

        // 2、放置几个按钮
        JButton b1 = new JButton("上");
        jPanel.add(b1);
        b1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往上跳
                move(Constant.UP);
            }
        });

        JButton b2 = new JButton("下");
        jPanel.add(b2);
        b2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往下蹲
                move(Constant.DOWN);
            }
        });

        JButton b3 = new JButton("左");
        jPanel.add(b3);
        b3.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往左走
                move(Constant.LEFT);
            }
        });

        JButton b4 = new JButton("右");
        jPanel.add(b4);
        b4.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往右走
                move(Constant.RIGHT);
            }
        });

        win.setLocationRelativeTo(null);
        win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        win.setVisible(true);
    }

    public static void move(int orientation){
        // 控制玛丽移动
        switch (orientation) {
            case Constant.UP:
                System.out.println("玛丽往↑飞了一下~~");
                break;
            case Constant.DOWN:
                System.out.println("玛丽往↓蹲了一下~~");
                break;
            case Constant.LEFT:
                System.out.println("玛丽往←跑了一下~~");
                break;
            case Constant.RIGHT:
                System.out.println("玛丽往→跑了一下~~");
                break;
        }
    }
}

 20:枚举  【信息标志和分类  使用 枚举  和 常量   登录用户名和信息这些还是使用常量】

枚举是Java中的一种特殊类型【特殊类】
枚举的作用:"是为了做信息的标志和信息的分类"。

定义枚举类的格式:
修饰符 enum 枚举名称{
  第一行都是罗列枚举类实例的名称。
}

enum Season{   
SPRING , SUMMER , AUTUMN , WINTER;}
enum Season{    
  SPRING , SUMMER , AUTUMN , WINTER;
}
// 当前枚举类的对象名称,4个季节对象,多例模式
反编译后观察枚举的特征:
Compiled from "Season.java"
public final class Season extends java.lang.Enum<Season> {
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season AUTUMN = new Season();
public static final Season WINTER = new Season();
public static Season[] values();
public static Season valueOf(java.lang.String);
}
枚举的特征:
  枚举类都是继承了枚举类型:java.lang.Enum
  枚举都是 final 最终类,不可以被继承。
  构造器都是私有的,枚举对外不能创建对象。
  枚举类的第一行默认都是罗列枚举对象的名称的。【每个名称都成存储的一个final 常量,而且是当前类的对象】
  枚举类相当于是多例模式 【对外不能创建对象,里面罗列出几个对象,几个变量创建几个对象】
package com.itheima.d5_enum;

public enum Constant {
    UP,DOWN,LEFT,RIGHT;
}
package com.itheima.d5_enum;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Test2 {
    public static void main(String[] args) {
        // 目标:使用枚举做信息标志和分类(最好的方案)
        // 1、创建窗口
        JFrame win = new JFrame("超级玛丽");
        win.setSize(300, 200);

        // 2、设计一个面板(桌布)
        JPanel jPanel = new JPanel();
        win.add(jPanel);

        // 2、放置几个按钮
        JButton b1 = new JButton("上");
        jPanel.add(b1);
        b1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往上跳
                move(Constant.UP);
            }
        });

        JButton b2 = new JButton("下");
        jPanel.add(b2);
        b2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往下蹲
                move(Constant.DOWN);
            }
        });

        JButton b3 = new JButton("左");
        jPanel.add(b3);
        b3.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往左走
                move(Constant.LEFT);
            }
        });

        JButton b4 = new JButton("右");
        jPanel.add(b4);
        b4.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 控制玛丽往右走
                move(Constant.RIGHT);
            }
        });

        win.setLocationRelativeTo(null);
        win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        win.setVisible(true);
    }

    public static void move(Constant orientation){
        // 控制玛丽移动
        switch (orientation) {    // switch兼容枚举类型,不需要 类名. 找对象,直接就能找到对象
            case UP:
                System.out.println("玛丽往↑飞了一下~~");
                break;
            case DOWN:
                System.out.println("玛丽往↓蹲了一下~~");
                break;
            case LEFT:
                System.out.println("玛丽往←跑了一下~~");
                break;
            case RIGHT:
                System.out.println("玛丽往→跑了一下~~");
                break;
        }
    }
}

 21:抽象类  abstract  【规范子类的行为】【抽象:设计图,不能实例化】

在Java中abstract是抽象的意思,可以修饰类、成员方法。
abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法。

修饰符 abstract class 类名{ 
    修饰符 abstract 返回值类型 方法名称(形参列表);
 }

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

注意事项
  抽象方法只有方法签名,不能声明方法体。
  一个类中如果定义了抽象方法,这个类必须声明成抽象类,否则报错

final 和 abstract:
  互斥关系
  final 修饰类不能被继承,abstract修饰类一般是要被继承的
  final修饰的方法一般不能被重写,abstract修饰的方法一般是要被重写的
抽象的使用场景:
  抽象类可以理解成不完整的设计图,一般作为父类,让子类来继承。
  当父类知道子类一定要完成某些行为,但是每个子类该行为的实现又不同,于是该父类就把该行为定义成抽象方法的形式,具体实现交给子类去完成。此时这个类就可以声明成抽象类
抽象类注意点:
  一个类继承了抽象类,那么这个类需要完成父类抽象类中的全部抽象方法,否则这个类也需要被定义成抽象类
public abstract class Animal public abstract void run(); }

如下案例:
  抽象类【父类】Animal 要求 子类 Dog 一定重写 run 这个实例方法【不重写 run 方法报错】
package com.itheima.d6_abstract;

/**
  抽象类:有abstract修饰
 */
public abstract class Animal {
    private String name;
    /**
       抽象方法:有abstract修饰 不能写方法体代码
     */
    public abstract void run();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.itheima.d6_abstract;

public class Dog extends Animal{
    @Override
    public void run() {
        System.out.println("狗跑的贼快~~");
    }
}

package com.itheima.d7_abstract_test;

public abstract class Card {
    private String userName;
    private double money;

    /**
       定义一个支付方法:表示卡片可以支付。
       抽象方法
     */
    public abstract void pay(double money2);

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}
package com.itheima.d7_abstract_test;

public class GoldCard extends Card{
    @Override
    public void pay(double money2) {
        System.out.println("您当前消费:" + money2);
        System.out.println("您卡片当前余额是:" + getMoney());
        // 优惠价:
        double rs = money2 * 0.8;
        System.out.println(getUserName() + ":您实际支付:" + rs);
        // 更新账户余额
        setMoney(getMoney() - rs);
    }
}
package com.itheima.d7_abstract_test;

public class Test {
    public static void main(String[] args) {
        // 目标:学习一下抽象类的基本使用:做父类,被继承,重写抽象方法
        GoldCard c = new GoldCard();
        c.setMoney(10000);
        c.setUserName("dlei");

        c.pay(300);
        System.out.println("剩余:" + c.getMoney());
    }
}
抽象类特征和注意事项
  类有的成员(成员变量、方法、构造器)抽象类都具备
  抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
  一个类继承了抽象类必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
  不能用abstract 修饰 变量、代码块、构造器 【只能修饰类和方法】
  最重要的特征:
    得到了抽象方法,失去了创建对象的能力(有得有失)【抽象类不能创建对象】
package com.itheima.d8_abstract_attention;

public class Test {
    public static void main(String[] args) {
        // 目标:理解抽象类的特征和注意事项。
        // 1、类有的东西,抽象类都有。
        // 2、抽象类中可以没有抽象方法,但是有抽象方法的必须是抽象类。
        // 3、一个类继承了抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
        // 4、抽象类不能创建对象 ,为什么??

        // 反证法:假如抽象类可以创建对象。
        // Animal a = new Animal();
        // a.run(); // run方法连方法体都没有! 因此抽象类不能创建对象。

       // Card c = new Card(); // 不行的,抽象类不能创建对象(这个观点不能动摇)。
    }
}

abstract  class Card{
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

abstract class Cat extends Animal{
    @Override
    public void run() {
    }
}

abstract class Animal{
    public abstract void run();
    public abstract void eat();
}

 22:模板设计方式 之  模板方法设计模式【抽象类 的实际使用--模板方法模式】

什么时候使用模板方法模式:
  使用场景说明:当系统中出现同一个功能多处在开发,而该功能中大部分代码是一样的,只有其中部分可能不同的时候。

模板方法模式实现步骤:
  1、定义一个抽象类。【模板功能定义成一个模板方法,放在抽象类中】
  2、定义2个方法,一个是模板方法:把相同代码放里面去,不同代码定义成抽象方法   3、子类继承抽象类,重写抽象方法。【模板方法不能决定的功能定义成抽象方法让具体子类去实现】

模拟方法建议使用 final 修饰:
  模板方法是给子类使用的,不是让子类重写的,一旦子类重写了模板方法,那么模板就失效了,加上 final 后可以防止子类重写模板方法。专业安全

package com.itheima.d9_abstract_template;

public abstract class Student {
    /**
       正式:声明了模板方法模式
       final :这个方法不能被子类重写,因为它是给子类直接使用的。
     */
    public final void write(){
        System.out.println("\t\t\t\t《我的爸爸》");
        System.out.println("你的爸爸是啥样,来说说:");

        // 正文部分(每个子类都要写的,每个子类写的情况不一样    [因此。模板方法把正文部分定义成抽象方法,交给具体的子类来完成)]
        System.out.println(writeMain());    // 子类调用这个方法的时候会调子类自己重写的方法

        System.out.println("我的爸爸简直太好了~~");
    }

    public abstract String writeMain();
}
package com.itheima.d9_abstract_template;

public class StudentChild extends Student{
    @Override
    public String writeMain() {
        return "的爸爸太牛b了,他总是买东西给我吃。。";
    }
}
package com.itheima.d9_abstract_template;

public class StudentMiddle extends Student{
    @Override
    public String writeMain() {
        return  "我的爸爸也很牛,我开车都不看红绿灯的," +
                "下辈子还要做他儿子~~";
    }
}
package com.itheima.d9_abstract_template;

public class Test {
    public static void main(String[] args) {
        // 目标:理解模板方法模式的思想和使用步骤。
        StudentMiddle s = new StudentMiddle();
        s.write();

        StudentChild s2 = new StudentChild();
        s2.write();
    }
}

23:面向对象之  接口    interface【也是一种代码规范,约定人家只能干啥,比抽象类约束性更强】

接口的定义与特点
接口的格式如下:
接口用关键字interface来定义
public interface 接口名 {
       // 常量    static final 修饰的变量
       // 抽象方法   abstract修饰的方法
} 

JDK8之前接口中只能是抽象方法和常量,没有其他成分了。
接口不能实例化。
接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化。
package com.itheima.d10_interface;

/**
   声明了一个接口: 体现一种规范,规范一定是公开的。
 */
public interface InterfaceDemo {
    // 目标:接口中的成分特点:JDK 8之前接口中只能有抽象方法和常量。
    // 1、常量:
    // 注意:由于接口体现规范思想,规范默认都是公开的,所以代码层面,public static final 可以省略不写【自动加】
     String SHCOOL_NAME = "天才程序员";
    //public static final String SHCOOL_NAME = "天才程序员";

    // 2、抽象方法
    // 注意:由于接口体现规范思想,规范默认都是公开的,所以代码层面,public abstract可以省略不写【自动加】
    void run();
    // public abstract void run();

    void eat();
    // public abstract void eat();
}

 24:接口的基本使用  被类实现  implements

接口的用法:
  接口是用来被类实现(implements)的,实现接口的类称为实现类。实现类可以理解成所谓的子类

修饰符 class 实现类 implements 接口1, 接口2, 接口3 , ... {
}
实现的关键字:
implements 上面可以看出,接口可以被类单实现,也可以被类多实现。 接口实现的注意事项:   一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类
package com.itheima.d11_interface_implements;

/**
   规范
 */
public interface SportMan {
    void run();     // 运动员一点要跑步
    void competition(); // 运动员一点要比赛
}
package com.itheima.d11_interface_implements;

public interface Law {
    void rule();// 遵纪守法
}
package com.itheima.d11_interface_implements;

/**
   实现类。
 */
public class PingPongMan implements SportMan, Law{
    private String name;
    public PingPongMan(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + "必须跑步训练!");
    }

    @Override
    public void competition() {
        System.out.println(name + "要参加比赛,为国争光~!");
    }

    @Override
    public void rule() {
        System.out.println(name + "必须守法~~");
    }
}
package com.itheima.d11_interface_implements;

public class Test {
    public static void main(String[] args) {
        // 目标:理解接口的基本使用:被类实现。
        PingPongMan p = new PingPongMan("张继科");
        p.run();
        p.competition();
        p.rule();
    }
}

25:接口与接口的关系  【接口支持多继承】

类和类的关系:单继承。
类和接口的关系:多实现。
接口和接口的关系:多继承,一个接口可以同时继承多个接口

接口多继承的作用
  规范合并,整合多个接口为同一个接口,便于子类实现。
package com.itheima.d12_interface_extends;

public interface Law {
    void rule();
}
package com.itheima.d12_interface_extends;

public interface People {
    void eat();
    void sleep();
}
package com.itheima.d12_interface_extends;

/**
   接口可以多继承:一个接口可以同时继承多个接口。
 */
public interface SportMan extends Law, People {
    void run();
    void competition();
}
package com.itheima.d12_interface_extends;

/**
   一个实现类的:
 */
public class BasketBallMan implements SportMan{
    @Override
    public void rule() {
    }
    @Override
    public void eat() {
    }
    @Override
    public void sleep() {

    }
    @Override
    public void run() {

    }
    @Override
    public void competition() {

    }
}

26:JDK8新增接口相关方法  允许接口中直接定义带有方法体的方法【接口不再存粹】

第一种:默认方法  【普通实例方法  使用 default 修饰】
  类似之前写的普通实例方法:必须用default修饰
  默认会public修饰。需要用接口的实现类的对象来调用
default void run(){
    System.out.println("--开始跑--");
}

第二种:静态方法
  默认会public修饰,必须static修饰。
  注意:接口的静态方法必须用本身的接口名来调用 【实现类名字 无法调用】
static void inAddr(){
   System.out.println("我们都在黑马培训中心快乐的学习Java!");
}

第三种:私有方法  【本接口被其他默认方法和私有方法访问】
  就是私有的实例方法:,必须使用private修饰,从JDK 1.9才开始有的。
  只能在本类中被其他的默认方法或者私有方法访问
private void go(){
    System.out.println("--准备--");
}

package com.itheima.d13_interface_jdk8;

public interface SportMan {
    /**
       1、默认方法:其实就是实例方法。【接口不能创建对象,这个方法只能过继给实现类,由实现类对象调用】
           -- 必须用default修饰,默认会自带public
           -- 必须用接口的实现类的对象来调用
     */
    default void run(){
        go();
        System.out.println("==跑的贼溜==");
    }
    /**
      2、静态方法
            -- 必须static修饰,默认会自带public
            -- 必须用接口名自己调用
     */
    static void inAddr(){
        System.out.println("我们在黑马");
    }
    /**
      3、私有实例方法:
           -- 必须用private修饰
           -- 只能本接口中访问。
           -- 一般给接口中其他的默认方法或者私有实例方法使用的
     */
    private void go(){
        System.out.println("开始跑~~");
    }
}
package com.itheima.d13_interface_jdk8;
// 实现类
public class PingPongMan implements SportMan{
}
package com.itheima.d13_interface_jdk8;

public class Test {
    public static void main(String[] args) {
        // 目标:理解JDK 8开始接口新增的方法。
        PingPongMan p = new PingPongMan();
        p.run();
        SportMan.inAddr();
    }
}
接口的注意事项
  1、接口不能创建对象【接口构造器,更加彻底的抽象】
  2、一个类实现多个接口,多个接口的规范不能冲突
  2、一个类实现多个接口,多个接口中有同样的静态方法不冲突。【静态方法只能 接口的名称去调用,所以不会冲突,接口里子类调用不了父类的静态方法】
  3、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。【优先使用父类的,毕竟亲爹】
  4、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可【子类使用不了 接口 干爹的方法】
  5、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承 【两个规范方法,一个方法有返回值,一个方法没有返回值这种,就不行,规范不能冲突】
package com.itheima.d14_interface_attention;
public class Test {
    public static void main(String[] args) {
        // 目标:了解接口使用的注意事项。
//        1、接口不能创建对象
          // A a = new A();

//        2、一个类实现多个接口,多个接口的规范不能冲突

//        3、一个类实现多个接口,多个接口中有同样的静态方法不冲突。(接口的静态方法只能接口自己调)
           A.test();
           B.test();
//        4、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。
          Zi zi = new Zi();
          zi.go();

//        5、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
        Zi2 zi2 = new Zi2();
        zi2.sing();

//        6、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承。

    }
}
//        6、一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突则不能多继承。
//interface K extends I, J{
//
//}
//interface I{
//    void run();
//}
//
//interface J{
//    String run();
//}

//    5、一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
class Zi2 implements GanDie1, GanDie2{
    @Override
    public void sing() {
         GanDie1.super.sing();
         GanDie2.super.sing();
         System.out.println("我唱给大家听了");
    }
}

interface GanDie1{
    default void sing(){
        System.out.println("干爹1让你唱小苹果~");
    }
}

interface GanDie2{
    default void sing(){
        System.out.println("干爹2让你唱征服~");
    }
}

// 4、一个类继承了父类,同时又实现了接口,父类中和接口中有同名方法,默认用父类的。
class Zi extends Fu implements GanDie{
    public void go(){
        GanDie.super.run(); // 找干爹这个爸爸的run方法。
    }
}
class Fu {
    public void run(){
        System.out.println("亲爹说赶紧跑路~~");
    }
}
interface GanDie{
    default void run(){
        System.out.println("干爹说留在我身边~~");
    }
}

/**
   接口是干爹。
 */
class C implements A, B{
    @Override
    public void run() {
    }
}

interface B{
    void run();
    static void test(){
    }
}

interface A{
    void run();
    static void test(){
    }
}

 27:面向对象之  多态    父类类型 对象名称 = new 子类构造器;  【有继承关系才有多态】

什么是多态?
  指对象可以有多种形态。【子类覆盖父类的方法,定义很多同类型的对象,执行同一个行为,会出现不同的行为特征】

多态的常见形式:
  父类类型 对象名称 = new 子类构造器;
  接口 对象名称 = new 实现类构造器; 多态中成员访问特点   方法调用:编译看左边,运行看右边。   变量调用:编译看左边,运行也看左边。(注意) 多态的前提   有继承
/实现关系;有父类引用指向子类对象;有方法重写(多态侧重行为多态)。
package com.itheima.d1_polymorphic;

class Animal {
    public String name = "动物名称";
    public void run(){
        System.out.println("动物可以跑~~");
    }
}

class Dog extends Animal{
    public String name = "狗名称";
    @Override
    public void run() {
        System.out.println("🐕跑的贼溜~~~~~");
    }
}

class Tortoise extends Animal{
    public String name = "乌龟名称";

    @Override
    public void run() {
        System.out.println("🐢跑的非常慢~~~");
    }
}

public class Test001 {
    public static void main(String[] args) {
        // 目标:先认识多态的形式
        // 父类  对象名称 = new 子类构造器();  狗也是属于动物类型,动物范围大,小类型变量给一个大类型,可以这样操作  
    // 【同类型变量 a和 a1都是Animal类型,调用同一行为,但是行为特征不同---多态】
Animal a = new Dog(); a.run(); // 方法调用:编译看左,运行看右 所以Animal里还是要定义这个 run 方法,不然编译报错的,子类里还要进行方法重写 System.out.println(a.name); // 变量调用:编译看左,运行也看左,动物名称 所以访问的还是Animal这个对象里定义的name, Animal a1 = new Tortoise(); a1.run(); System.out.println(a1.name); // 动物名称 } }

28:面向对象之  多态的优势

优势
  在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
  Animal a = new Dog();
  a.run(); // 后续业务行为随对象而变,后续代码无需修改   【可以使用 Dog  也可以使用 Tortoise】

定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利。
  【父类类型对象可以接收一切子对象】
多态下会产生的一个问题:   多态下不能使用子类的独有功能【使用强制类型转换解决】
public static void go(Animal a){
    }
这个方法可以接收一切 Animal和他子类对象,可以是Dog对象也可以是 Tortoise 对象,
方法的扩展性更强也更更便利 【多态使用的案例】
多态下不能使用子类的独有功能:
package com.itheima.d2_polymorphic_advantage;

/**
    父类
 */
public class Animal {
    public String name = "动物名称";
    public void run(){
        System.out.println("动物可以跑~~");
    }
}
package com.itheima.d2_polymorphic_advantage;

public class Dog extends Animal {
    public String name = "狗名称";
    @Override
    public void run() {
        System.out.println("🐕跑的贼溜~~~~~");
    }
    /**
      独有功能
     */
    public void lookDoor(){
        System.out.println("🐕在看🚪!!!");
    }
}
package com.itheima.d2_polymorphic_advantage;

public class Tortoise extends Animal {
    public String name = "乌龟名称";

    @Override
    public void run() {
        System.out.println("🐢跑的非常慢~~~");
    }
}
package com.itheima.d2_polymorphic_advantage;

public class Test {
    public static void main(String[] args) {
        Animal d = new Dog();
        go(d);
        // d.lookDoor();    Dog类这个子类对象的独有功能无法使用多态这种模式调用 【编译阶段看左边,Animal这个类没有 lookDoor 这个方法,不能调用 子类独有方法】
        Animal t = new Tortoise();
        go(t);
    }

    /**
       希望这个方法可以接收一切子类动物对象
     * @param a
     */
    public static void go(Animal a){
        System.out.println("预备~~~");
        a.run();
        System.out.println("结束~~~~");
    }
}

29:多态  之   引用数据类型的类型转换    【自动类型转换】【强制类型转换】

自动类型转换(从子到父):子类对象赋值给父类类型的变量指向 【向上转型,父类在上,子类在下】
    Animal c = new Cat();
强制类型转换(从父到子): 从父到子( 必须进行强制类型转换,否则报错): 子类 对象变量
= (子类)父类类型的变量 作用:可以解决多态下的劣势,可以实现调用子类独有的功能。 注意: 有继承/实现关系的类就可以在编译阶段进行强制类型转换;但是,如果转型后的类型和对象真实对象的类型不是同一种类型,那么在运行代码时,就会出现ClassCastException     Animal c = new Cat();     Dog d = (Dog)c; // 出现异常 ClassCastException Java建议强转转换前使用 instanceof 判断当前对象的真实类型,再进行强制转换 变量名 instanceof 真实类型 判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true,反之。
package com.itheima.d3_polymorphic_convert;

/**
     目标:学习多态形式下的类中转换机制。
 */
public class Test {
    public static void main(String[] args) {
        // 自动类型转换
        Animal a = new Dog();
        a.run();
//        a.lookDoor(); // 多态下无法调用子类独有功能

        // 强制类型转换:可以实现调用子类独有功能的
        Dog d = (Dog) a;
        d.lookDoor();

        // 注意:多态下直接强制类型转换,可能出现类型转换异常
        // 规定:有继承或者实现关系的2个类型就可以强制类型转换,运行时可能出现问题。
        // Tortoise t1 = (Tortoise) a;  // 把狗转成乌龟
        // 建议强制转换前,先判断变量指向对象的真实类型,再强制类型转换。 【为了避免报错】
        if(a instanceof Tortoise){
            Tortoise t = (Tortoise) a;
            t.layEggs();
        }else if(a instanceof Dog){
            Dog d1 = (Dog) a;
            d1.lookDoor();
        }

        System.out.println("---------------------");
        Animal a1 = new Dog();
        go(a1);
    }

    public static void go(Animal a){
        System.out.println("预备~~~");
        a.run();
        // 独有功能
        if(a instanceof Tortoise){
            Tortoise t = (Tortoise) a;
            t.layEggs();
        }else if(a instanceof Dog){
            Dog d1 = (Dog) a;
            d1.lookDoor();
        }
        System.out.println("结束~~~~");
    }
}
引用数据类型的类型转换,有几种方式?
  自动类型转换、强制类型转换。
强制类型转换能解决什么问题?
  可以转换成真正的子类类型,从而调用子类独有功能。
强制类型转换需要注意什么?
  有继承关系/实现的2个类型就可以进行强制转换,编译无问题。
  运行时,如果发现强制转换后的类型不是对象真实类型则报错(ClassCastException)
强制类型转换前最好做什么事情,如何进行?
  使用instanceof判断当前对象的真实类型,再进行强制转换
  对象变量名 instanceof 真实类型
多态+接口+抽象类综合案例

package com.itheima.d4_polymorphic_test;

public interface USB {
    void connect();
    void unconnect();
}
package com.itheima.d4_polymorphic_test;

/**
   实现类(子类)键盘
 */
public class KeyBoard implements USB{
    private String name;

    public KeyBoard(String name) {
        this.name = name;
    }

    @Override
    public void connect() {
        System.out.println(name + "成功的接入了设备了~~~");
    }

    @Override
    public void unconnect() {
        System.out.println(name + "成功的从设备弹出了~~~");
    }

    /**
      独有功能
     */
    public void keyDown(){
        System.out.println(name + "写下了:老铁,6666,下次再来哦,老弟~~~~");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.itheima.d4_polymorphic_test;

/**
   实现类(子类)鼠标
 */
public class Mouse implements USB{
    private String name;

    public Mouse(String name) {
        this.name = name;
    }

    @Override
    public void connect() {
        System.out.println(name + "成功的接入了设备了~~~");
    }

    @Override
    public void unconnect() {
        System.out.println(name + "成功的从设备弹出了~~~");
    }

    /**
      独有功能
     */
    public void click(){
        System.out.println(name + "双击点亮小红心~~~~");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.itheima.d4_polymorphic_test;

public class Computer {
    /**
       提供一个安装的入口:行为。 【按照 任何 usb设备,所以传参定义为usb类型】
     */
    public void installUSB(USB u){
        u.connect();

        // 独有功能 【强制类型转换才能调用独有功能】
        if(u instanceof Mouse){
            Mouse m = (Mouse) u;
            m.click();
        }else if(u instanceof KeyBoard) {
            KeyBoard k = (KeyBoard) u;
            k.keyDown();
        }
        u.unconnect();
    }
}
package com.itheima.d4_polymorphic_test;

/**
    目标:USB设备模拟
    1、定义USB接口:接入 拔出
    2、定义2个USB的实现类:鼠标、键盘。
    3、创建一个电脑对象,创建USB设备对象,安装启动。
 */
public class Test {
    public static void main(String[] args) {
        // a、创建电脑对象
        Computer c = new Computer();
        // b、创建USB设备对象
        USB u = new Mouse("罗技鼠标");
        c.installUSB(u);

        USB k = new KeyBoard("双飞燕键盘");
        c.installUSB(k);
    }
}

30:内部类      静态内部类  对象内部类  局部内部类

内部类:内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。
public class People{
    // 内部类    public class Heart{
    }
}
内部类的使用场景
  场景:当一个事物的内部,还有一个部分需要一个完整的结构进行描述时。这个内部的完整结构又只为外部事物提供服务,那么整个内部的完整结构可以自己选择使用内部类设计
  【比如 汽车类 里 有个 发动机类 人类 里 心脏类】
基本作用   内部类通常可以方便访问外部类的成员,包括私有的成员。   内部类提供了更好的封装性,内部类本身就可以用 privateprotectecd 等修饰,封装性可以做更多控制【外部类 只能使用 pubulic 和 缺省 修饰】
  pubulic:任何地方可以访问
  缺省:当前包里可以被访问 内部类的分类   静态内部类[了解]   成员内部类(非静态内部类) [了解]   局部内部类[了解]   匿名内部类(重点)
静态内部类?
  有static修饰,属于外部类本身。
  它的特点和使用与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已。
public class Outer{
        // 静态成员内部类
        public static class Inner{
        }
}
静态内部类创建对象的格式:    
  格式:外部类名.内部类名 对象名 = new 外部类名.内部类构造器;
  范例:Outer.Inner in =  new Outer.Inner();

静态内部类的访问拓展:    
  1、静态内部类中是否可以直接访问外部类的静态成员? 
    可以,外部类的静态成员只有一份可以被共享访问。
  2、静态内部类中是否可以直接访问外部类的实例成员? 
    不可以的,外部类的实例成员必须用外部类对象访问。

静态内部类的使用场景、特点、访问总结。
  如果一个类中包含了一个完整的成分,如汽车类中的发动机类。 
  特点、使用与普通类是一样的,类有的成分它都有,只是位置在别人里面而已。
  访问总结:可以直接访问外部类的静态成员,不能直接访问外部类的实例成员。
  注意:开发中实际上用的还是比较少。
package com.itheima.d5_innerclass_static;
/**
   外部类
 */
public class Outer {

    public static int a = 100;
    private String hobby;

    /**
       学习静态成员内部类
     */
    public static class Inner{
        private String name;  // 实例成员变量
        private int age;
        public static String schoolName;  // 静态成员变量
        public Inner(){}    // 无参构造器
        public Inner(String name, int age) {  // 有参构造器
            this.name = name;
            this.age = age;
        }
        public void show(){    // 普通实例方法
            System.out.println("名称:" + name);
            System.out.println(a);
            // System.out.println(hobby); // 报错!【不能访问外部类的 实例 变量】
//            Outer o = new Outer();    // 创建对象可以间接访问 外部类的 实例变量
//            System.out.println(o.hobby);
        }
        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;
        }
    }
}
package com.itheima.d5_innerclass_static;

public class Test {
    public static void main(String[] args) {
        Outer.Inner in = new Outer.Inner();
        in.setName("张三");
        in.show();
    }
}
成员内部类?【也叫 实例 内部类,属于对象】
  无static修饰,属于外部类的对象。
  JDK16之前,成员内部类中不能定义静态成员,JDK 16开始也可以定义静态成员了。
public class Outer {
    // 成员内部类
    public class Inner {    
    }
}
成员内部类创建对象的格式:    
  格式:外部类名.内部类名 对象名 = new  外部类构造器.new 内部类构造器();
  范例:Outer.Inner in = new Outer().new Inner(); 成员内部类的访问拓展:   1、成员内部类中是否可以直接访问外部类的静态成员?     可以,外部类的静态成员只有一份可以被共享访问。   2、成员内部类的实例方法中是否可以直接访问外部类的实例成员?     可以的,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员。
package com.itheima.d6_innerclass;

/**
   外部类
 */
public class Outer {
    public static int num = 111;
    private String hobby;
    public Outer() {
    }
    public Outer(String hobby) {
        this.hobby = hobby;
    }

    /**
       成员内部类:不能加static修饰 属于外部类对象的
     */
    public class Inner{
        private String name;  // 实例成员
        private int age;
        public static int a = 100; // JDK 16开始支持静态成员了

        public static void test(){  // 静态方法
            System.out.println(a);
        }
        public void show(){    // 普通实例方法
            System.out.println("名称:" + name);
            System.out.println("数量:" + num);    // 访问外部类的 静态 变量
            System.out.println("爱好:" + hobby);    // 访问外部类的 成员 变量
        }
        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;
        }
    }
}
package com.itheima.d6_innerclass;

public class Test {
    public static void main(String[] args) {
        Outer.Inner in = new Outer().new Inner();
        in.setName("内部");
        in.show();
        Outer.Inner.test();  // 访问 成员内部类 静态方法
        System.out.println("------------");
        Outer.Inner in1 = new Outer("爱听课").new Inner();
        in1.show();
    }
}
package com.itheima.d6_innerclass;

public class Test2 {
    public static void main(String[] args) {
        People.Heart heart = new People().new Heart();
        heart.show();
    }
}

class People{
    private int heartbeat = 150;

    /**
       成员内部类
     */
    public class Heart{
        private int heartbeat = 110;

        public void show(){
            int heartbeat = 78;
            System.out.println(heartbeat); // 78
            System.out.println(this.heartbeat); // 110
            System.out.println(People.this.heartbeat); // 150  访问所寄生 外部类的 对象
        }
    }
}

TIPS:在成员内部类中,访问所在的外部类对象,  格式:外部类名.this
局部内部类 (鸡肋语法,了解即可)
  局部内部类放在方法、代码块、构造器等执行体中。
  局部内部类的类文件名为: 外部类$N内部类.class
package com.itheima.d7_innerclass;
/**
    目标:了解局部内部类的语法
 */
public class Test {
    static {
         class Dog{
         }
         abstract class Animal{
         }
         interface SportManInter{
         }
    }

    public static void main(String[] args) {
        class Cat{
            private String name;
            public static int onLineNumber = 100;
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
        }
        interface SportManInter{
        }
        Cat c = new Cat();
        c.setName("叮当猫~");
        System.out.println(c.getName());
    }
}

31:内部类      匿名内部类

匿名内部类:
  本质上是一个没有名字的局部内部类。【定义在方法中,代码块中】
  作用:方便创建子类对象,最终目的是为了简化代码编写。

格式:【直接创建子类对象需要 定义父类子类继承,然后再创建子类对象,匿名内部类绕过子类这一部分,直接得到子类对象】
new 类|抽象类名|或者接口名() {
    重写方法;
};

Employee a = new Employee() {
    public void work() {
    }
};
a. work();

特点总结:
  匿名内部类是一个没有名字的内部类,同时也代表一个对象。
  匿名内部类产生的对象类型,相当于是当前new的那个的类型的子类类型

匿名内部类的作用?
  方便创建子类对象,最终目的为了简化代码编写。
匿名内部类的格式?
Animal a = new Employee() {
    public void run() {
    }
};
a. run();

匿名内部类的特点?
  匿名内部类是一个没有名字的内部类,【运行编译的时候会产生一个class 文件】
  匿名内部类写出来就会产生一个匿名内部类对象   匿名内部类的对象类型,相当于是当前new的那个类型的子类类型。【多态形式的写法】
package com.itheima.d8_innerclass_anonymous;

/**
      目标:学习匿名内部类的形式和特点。  如下,匿名内部类 不需要依赖 Tiger 这个类实现子类,直接实现 【快速构建对象,不需要实现子类】
 */
public class Test {
    public static void main(String[] args) {
        Animal a = new Animal(){
            @Override
            public void run() {
                System.out.println("老虎跑的块~~~");
            }
        };
        a.run();
    }
}

//class Tiger extends Animal{
//    @Override
//    public void run() {
//        System.out.println("老虎跑的块~~~");
//    }
//}

abstract class Animal{
    public abstract void run();
}
匿名内部类使用案例:

package com.itheima.d8_innerclass_anonymous;

/**
    目标:掌握匿名内部类的使用形式(语法)
 */
public class Test2 {
    public static void main(String[] args) {
        Swimming s = new Swimming() {
            @Override
            public void swim() {
                System.out.println("学生快乐的自由泳🏊‍");
            }
        };
        go(s);
        System.out.println("--------------");
        Swimming s1 = new Swimming() {
            @Override
            public void swim() {
                System.out.println("老师泳🏊的贼快~~~~~");
            }
        };
        go(s1);
        System.out.println("--------------");
        go(new Swimming() {
            @Override
            public void swim() {
                System.out.println("运动员🏊的贼快啊~~~~~");
            }
        });
    }
    /**
       学生 老师 运动员可以一起参加游泳比赛
     */
    public static void go(Swimming s){
        System.out.println("开始。。。");
        s.swim();
        System.out.println("结束。。。");
    }
}

interface Swimming{
    void swim();
}
匿名内部类使用场景:

package com.itheima.d8_innerclass_anonymous;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
   目标:通过GUI编程 理解匿名内部类的真实使用场景
 */
public class Test3 {
    public static void main(String[] args) {
        // 1、创建窗口
        JFrame win = new JFrame("登录界面");
        JPanel panel = new JPanel();    // 定义一个桌布 【桌布可以自己布局,默认布局,自动使用按钮大小,窗口不行,窗口直接铺满】
        win.add(panel);    // 桌布放到 界面

        // 2、创建一个按钮对象
        JButton btn = new JButton("登录");

        // 注意:讲解匿名内部类的使用  【按钮绑定一个监听器,才让别人知道有没有点击操作按钮】  方法入参是一个 ActionListener 接口监听器对象
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(win, "点我一下,说明爱我!");
            }
        });

//        btn.addActionListener( e ->  JOptionPane.showMessageDialog(win, "别说话,吻我!!") );
        // 3、把按钮对象添加到桌布上展示
        panel.add(btn);

        // 4、展示窗口
        win.setSize(400, 300);
        win.setLocationRelativeTo(null);  //居中
        win.setVisible(true);
    }
}

 

posted @ 2023-04-25 02:22  至高无上10086  阅读(7)  评论(0编辑  收藏  举报