Skip to content

day11.内部类

java
课前回顾:
  1.接口:是一种标准,规范
    a.关键字:interface
    b.实现关键字:implements
  2.抽象方法 -> 不写abstract默认也有
    重写 -> 创建实现类对象,调用重写功能
  3.默认方法 -> 带default
    可重写,可不重写 -> 创建实现类对象,调用默认方法
  4.静态方法 -> 接口名直接调用
  5.成员变量 -> 被public static final修饰,不写也有
    接口名直接调用
  6.私有方法 -> private的
    只能在接口内部直接调用
  7.接口的特点:
    a.可以多实现
    b.可以多继承
    c.一个类继承一个父类的同时实现一个或者多个接口
  8.多态:
    a.前提:
      必须有子父类继承关系或者接口实现关系
      必须有方法的重写
      父类引用指向子类对象
    b.成员访问特点:
      成员变量:看等号左边是说
      成员方法:看new的是谁
    c.好处:扩展性强 -> 父类可以接收任何它的子类对象,接收哪个子类对象,就指向哪个子类对象,就会动态调用哪个子类对象重写的方法
    d.向下转型:
      Fu fu = new Zi()    -> long i = 10;
      Zi zi = (Zi)fu      -> int j = (int)i;
    e.强转时出现的问题:ClassCastException()类型转换异常 -> 等号左右两边类型不一致
    f.判断类型 ->
      对象名 instanceof 类型 -> 判断关键字前面的对象是否属于关键字后面的类型
      对象名 instanceof 类型 对象名 -> 判断关键字前面的对象是否属于关键字后面的类型,会自动强转
  9.权限修饰符:
    public -> protected -> 默认 -> private

    属性用private -> 封装思想
    构造用public -> 便于创建对象
    方法用public -> 方便调用
  10.final -> 最终的
     a.final修饰类 ->不能被继承
     b.final修饰方法 -> 不能被重写,不能和abstract一起使用
     c.final修饰成员变量 -> 不能二次赋值,需要手动赋值
     d.final修饰局部变量 -> 不能被二次赋值
     e.final修饰对象 -> 地址值不能变,但是属性可以改变

今日重点:
  1.会静态代码块的使用以及使用场景
  2.会匿名内部类
  3.会使用lombok工具快速编写javabean
  4.会使用单元测试

第一章.代码块

1.1 构造代码块

java
1.格式:
  {
    代码
  }
2.执行特点:
  优先于构造方法执行,而且每new一次就会执行一次
java
public class Person {
    public Person(){
        System.out.println("构造方法");
    }

    //构造代码块
    {
        System.out.println("构造代码块");
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        Person person1 = new Person();
    }
}

1.2 静态代码块

java
1.格式
  static{
    代码
  }
2.执行特点:
  优先于构造代码块以及构造方法执行,只执行一次
java
public class Person {
    public Person(){
        System.out.println("构造方法");
    }

    //构造代码块
    {
        System.out.println("构造代码块");
    }

    //静态代码块
    static{
        System.out.println("静态代码块");
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        Person person1 = new Person();
    }
}

按照执行优先级来看: 静态代码块>构造代码块>构造方法

1.3.静态代码块使用场景

java
1.如果有一些数据,需要先初始化而且只需要初始化一次反复使用,那么这些数据就可以放到静态代码块中去初始化
1742953846250

第二章.内部类

java
1.什么时候使用内部类:
  当一个事物的内部,还有一个部分需要完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类
  比如:人类都有心脏,人类本身需要用属性,行为去描述,那么人类内部的心脏也需要心脏特殊的属性和行为来描述,此时心脏就可以定义成内部类,人类中的一个内部类

  当一个类内部的成员也需要用属性和行为描述时,就可以定义成内部类了

2.在java中允许一个类的定义位于另外一个类内部,前者就称之为内部类,后者称之为外部类
  class A{
      class B{

      }
  }
  A就是B的外部类
  B就是A的内部类

3.分类:
  成员内部类(静态,非静态)
  局部内部类
  匿名内部类(重点) -> 匿名内部类属于局部内部类一种

1 静态成员内部类

java
1.格式:直接在定义内部类的时候加上static关键字即可
  public class A{
      static class B{

      }
  }

2.注意:
  a.内部类中可以定义属性,方法,构造等
  b.静态内部类可以被final或者abstract修饰
    给final修饰,不能被继承
    被abstract修饰,不能new
  c.静态内部类不能调用外部的非静态成员
  d.内部类还可以被四种权限修饰符修饰

3.调用静态内部类成员:
  外部类.内部类 对象名 = new 外部类.内部类()
java
public class Person {
    public void eat(){
        System.out.println("人要干饭");

        //jump();

        //new Heart().jump();
    }

    /**
     * 静态成员内部类
     */
    static class Heart{
        public void jump(){
            System.out.println("心脏咣咣咣地跳动");
            //new Person().eat();
        }
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Person.Heart heart = new Person.Heart();
        heart.jump();
    }
}

2 非静态成员内部类

java
1.格式:
  public class 类名{
      class 类名{

      }
  }

2.注意:
  a.内部类中可以定义属性,方法,构造等
  b.静态内部类可以被final或者abstract修饰
    给final修饰,不能被继承
    被abstract修饰,不能new
  c.静态内部类不能调用外部的非静态成员
  d.内部类还可以被四种权限修饰符修饰

3.调用非静态成员内部类
  外部类.内部类 对象名 = new 外部类().new 内部类()
java
public class Person {
    public void eat() {
        System.out.println("人要干饭");

        //jump();

        //new Heart().jump();
    }

    /**
     * 非静态成员内部类
     */
    class Heart {
        public void jump() {
            System.out.println("心脏咣咣咣地跳动");
            //new Person().eat();
        }
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Person.Heart heart = new Person().new Heart();
        heart.jump();
    }
}

外部类的成员变量和内部类的成员变量以及内部类的局部变量重名时,怎么区分?

java
public class Student {
    String name = "张三";//外部类成员变量
    class Heart{
        String name = "李四";//内部类成员变量
        public void dispaly(){
            String name = "王五";//内部类局部变量
            System.out.println(name);//王五
            System.out.println(this.name);//李四
            System.out.println(Student.this.name);//张三
        }
    }
}

3.局部内部类

3.1.局部内部类基本操作

java
1.可以定义在方法中,代码块中,构造方法中
java
public class Person {
    public void eat(){
        /**
         * 局部内部类
         */
        class Heart{
            public void jump(){
                System.out.println("跳跳跳跳跳跳");
            }
        }

        Heart heart = new Heart();
        heart.jump();
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.eat();
    }
}

1.2.局部内部类实际操作

1.2.1.接口类型作为方法参数传递和返回

1.接口作为方法参数传递,传递的是实现类对象

2.接口作为方法返回值类型,返回的也是实现类对象

java
public interface USB {
    public abstract void open();
}
java
public class Mouse implements USB{
    @Override
    public void open() {
        System.out.println("鼠标开启了");
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Mouse mouse = new Mouse();
        method01(mouse);
        System.out.println("=================");
        USB usb = method02();// USB usb = mouse
        usb.open();
    }

    /**
     * 接口类型作为方法参数传递,实际上传递的是实现类对象
     * @param usb
     */
    public static void method01(USB usb){//USB usb = mouse
        usb.open();
    }

    /**
     * 接口作为返回值类型,最终返回的是实现类对象
     * @return
     */
    public static USB method02(){
        Mouse mouse = new Mouse();
        return mouse;
    }
}

1.2.2.抽象类作为方法参数和返回值

1.抽象类作为方法参数传递,应该接收子类对象

2.抽象类作为方法返回值类型,返回的是子类对象

java
public abstract class Animal {
    public abstract void eat();
}
java
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗啃骨头");
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        method01(dog);
        System.out.println("=============");
        Animal animal = method02();//Animal animal = dog
        animal.eat();
    }

    /**
     * 抽象类做方法参数传递,传递的实际上是子类对象
     * @param animal
     */
    public static void method01(Animal animal){//Animal animal = dog
        animal.eat();
    }

    /**
     * 抽象类做方法返回值类型,返回的实际上是子类对象
     * @return
     */
    public static Animal method02(){
        Dog dog = new Dog();
        return dog;
    }
}

1.2.3.普通类做方法参数和返回值

普通类作为方法参数传递,传递的是对象

普通类作为方法返回值类型返回,返回的也是对象

java
public class Person {
    public void eat(){
        System.out.println("人要吃软饭,软饭硬吃,养胃");
    }
}
java
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        method01(person);
        System.out.println("==================");
        Person person1 = method02();
        person1.eat();
    }

    /**
     * Person作为方法参数传递,传递的是对象
     * @param person
     */
    public static void method01(Person person){
        person.eat();
    }

    /**
     * Person作为返回值返回,返回的是对象
     * @return
     */
    public static Person method02(){
        Person person = new Person();
        return person;
    }
}

1.2.4.局部内部类实际操作

java
public interface USB {
    void open();
}
java
public class Test01 {
    public static void main(String[] args) {
        USB usb = method01();//USB usb = mouse
        usb.open();
    }

    public static USB method01(){
        class Mouse implements USB{
            public void open() {
                System.out.println("鼠标打开");
            }
        }

        Mouse mouse = new Mouse();
        return mouse;// return new Mouse()
    }
}

4.匿名内部类(重点)

java
1.匿名内部类是局部内部类的一种
2.上面的代码Mouse类就是一个局部内部类,我们在定义的时候,显式的定义出此局部内部类叫啥了(叫Mouse),所以我们可以理解为这是一个"有名的内部类",而且这个内部类做了接口的实现类使用

  如果我们在定义局部内部类的时候,不显式的将此内部类定义一个名字,那么我们就可以将这个内部类叫做"匿名内部类",当然,这个匿名内部类也作为接口的实现类使用

4.1.匿名内部类基本使用

java
1.格式1:利用有名对象去创建匿名内部类的对象
  接口名 对象名 = new 接口(){
     重写方法(){}
  } ;
  对象名.重写方法名();

2.格式2:利用匿名对象去创建匿名内部类的对象
  new 接口(){
     重写方法(){}
  }.重写的方法名();

3.使用场景:如果我们就想简单的去实现一下接口中的某个抽象方法,去直接调用,此时我们就需要
          a.创建实现类
          b.实现接口
          c.重写抽象方法
          d.创建实现类对象,调用重写方法

          所以我们没必要这么麻烦,我们只需要用匿名内部类创建对象,然后一个格式就包含了以上四步
java
public interface USB {
    void open();
    //void close();
}
java
public class Test01 {
    public static void main(String[] args) {
        /*
          格式1:利用有名对象创建匿名内部类对象

          USB usb = new Mouse()
          usb.open();
         */
        USB usb = new USB() {
            @Override
            public void open() {
                System.out.println("USB打开了");
            }

      /*      @Override
            public void close() {
                System.out.println("USB关闭了");
            }*/
        };
        usb.open();
        //usb.close();

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

        /*
          格式2:利用匿名对象创建匿名内部类对象

          new Mouse().open();
         */
        new USB() {
            @Override
            public void open() {
                System.out.println("USB打开了");
            }

           /* @Override
            public void close() {
                System.out.println("USB关闭了");
            }*/
        }.open();
    }
}
1742969980476

4.2 匿名内部类复杂用法_当参数传递

java
public interface USB {
    void open();
}
java
public class Test01 {
    public static void main(String[] args) {
        method01(new USB() {
            @Override
            public void open() {
                System.out.println("USB打开");
            }
        });
    }

    public static void method01(USB usb) {
        usb.open();
    }
}
1742971455799

4.3 匿名内部类复杂用法_当返回值返回

java
public interface USB {
    void open();
}
java
public class Test02 {
    public static void main(String[] args) {
        USB usb = method();
        usb.open();
    }

    public static USB method(){
        return new USB() {
            @Override
            public void open() {
                System.out.println("USB打开了");
            }
        };
    }
}
1742971861729

第三章.lombok

java
1.概述:Lombok属于第三方工具,使用第三方工具时需要导第三方提供给咱们得jar包
2.什么叫做jar包:jar包是一种压缩包,里面装的一般都是class文件
3.如何导入jar包:
  a.在当前模块下右键->new->Directory
  b.取名为lib或者libs
  c.将jar包粘贴到lib文件夹下
  d.对着要解压的jar包 -> 右键 -> add as library ->level选择module(此时上面有一个输入框叫name,name栏会变成空的) -> ok

    或者直接对着lib文件夹右键 -> add as library ->level选择module(此时上面有一个输入框叫name,name栏会变成空的) -> ok
1742974173487
java
1.lombok作用: 简化javabean开发的
1742974380359

1.lombok 介绍

Lombok 通过增加一些“处理程序”,可以让 javabean 变得简洁、快速。

Lombok 能以注解形式来简化 java 代码,提高开发效率。开发中经常需要写的 javabean,都需要花时间去添加相应的 getter/setter,也许还要去写构造器、equals 等方法,而且需要维护。

Lombok 能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString 方法。出现的神奇就是在源码中没有 getter 和 setter 方法,但是在编译生成的字节码文件中有 getter 和 setter 方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。

1730851674383

2.lombok 常用注解

@Getter 和@Setter

  • 作用:生成成员变量的 get 和 set 方法。
  • 写在成员变量上,指对当前成员变量有效。
  • 写在类上,对所有成员变量有效。
  • 注意:静态成员变量无效。

@ToString

  • 作用:生成 toString()方法。
  • 注解只能写在类上。

@NoArgsConstructor 和@AllArgsConstructor

  • @NoArgsConstructor:无参数构造方法。
  • @AllArgsConstructor:满参数构造方法。
  • 注解只能写在类上。

@EqualsAndHashCode

  • 作用:生成 hashCode()和 equals()方法。
  • 注解只能写在类上。

@Data

  • 作用:生成 get/set,toString,hashCode,equals,无参构造方法
  • 注解只能写在类上。
java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    private String name;
    private int age;
}
java
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("涛哥");
        person.setAge(18);
        System.out.println(person.getName()+"..."+person.getAge());
        System.out.println("=======================");
        Person person2 = new Person("小明", 18);
        System.out.println(person2.getName()+"..."+person2.getAge());
    }
}

第四章.单元测试

1.Junit 介绍

java
1.概述:是单元测试的一个小框架,用于测试方法,在一定程度上能代替main方法
2.使用:
  a.导入junit的jar包
  b.使用junit中的注解

2.Junit 的基本使用(重点)

java
1.注解:
  @Test  ->  放到方法上使用
java
public class Demo01Junit {
    @Test
    public void test01(){
        System.out.println("我是test01");
    }
}

3.Junit 的注意事项

java
1.被修饰的方法不能有参数
2.被修饰的方法不能有返回值
3.被修饰的方法不能是静态的

4.Junit 相关注解

java
1.@Before:在@Test之前执行,有多少个@Test修饰的方法执行@Before就执行多少次
2.@After:在@Test之后执行,有多少个@Test修饰的方法执行@After就执行多少次
java
public class Demo01Junit {
    @Test
    public void test01(){
        System.out.println("我是test01");
    }

    @Test
    public void test02(){
        System.out.println("我是test02");
    }

    @Before
    public void before01(){
        System.out.println("我是@Before");
    }

    @After
    public void after01(){
        System.out.println("我是@After");
    }
}

5.@Test 以后怎么使用

java
public class Demo02Junit {

    /**
     * 定义一个方法,专门测添加功能的
      */
    @Test
    public void insert(){
        boolean result = new CategoryImpl().insertCategory("服装", "箱包", "食品", "日用品");
        System.out.println("result = " + result);
    }

    /**
     * 定义一个方法,专门测查询功能的
     */
    @Test
    public void query(){
        ArrayList<String> list = new CategoryImpl().queryCategory();
        System.out.println("list = " + list);
    }
/*    public static void main(String[] args) {
        boolean result = new CategoryImpl().insertCategory("服装", "箱包", "食品", "日用品");
        System.out.println("result = " + result);

        ArrayList<String> list = new CategoryImpl().queryCategory();
        System.out.println("list = " + list);
    }*/
}
java
public class CategoryImpl {
    /**
     * 添加功能
     */

    public boolean insertCategory(String...arr){
        //创建集合,存储多个数据
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < arr.length; i++) {
            //往集合中添加元素
            list.add(arr[i]);
        }

        return true;
    }

    /**
     * 查询功能
     */
    public ArrayList<String> queryCategory(){
        //创建集合,存储多个数据
        ArrayList<String> list = new ArrayList<>();
        list.add("服装");
        list.add("箱包");
        list.add("食品");
        list.add("日用品");
        list.add("手机");
        list.add("电脑");
        list.add("电器");

        return list;
    }
}