面相对象-内部类&泛型&常用API

一.内部类

  • 内部类是类中五大成分之一(成员变量,方法,构造器,代码块,内部类)

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

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

(1)成员内部类

就是定义一个类中成员位置的类,在内部类中也可以定义成员属性和方法

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

1.成员内部中可以定义实例成员,静态成员(注意:静态成员从jdk16开始支持)

2.成员内部类中的实例方法,可以直接访问外部类的实例成员,静态成员

3.如果内部类和外部类出现了重名的成员,可以通过(外部类名.this.xxx)强行访问外部类的成员 

public class Car {

    //外部类的成员变量
    private String name = "宝马";

    //成员内部类
    public class Engine {

        private int power;

        private String name = "发动机";

        public static int price = 1000;

        //3、如果内部和外部类出现了重名的成员,可以通过(外部类名.this.xxx) 强行访问外部类的成员
        public void showName() {
            System.out.println("name=" + Car.this.name);
        }

        public int getPower() {
            return power;
        }

        public void setPower(int power) {
            this.power = power;
        }
    }
}
(2)静态内部类
  • 使用static修饰的内部类
  • 静态内部类中访问外部类成员的特点:可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员
  • 定义类的格式:

public class Outer{

     public static class Inner{

}

}

  • 创建对象的格式

外部类名.内部类名 对象名 = new 外部类(..).内部类(..); Outer.Inner in = new Outer().Inner();

  • public class Demo {
        public static void main(String[] args) {
            //创建静态内部类对象
            Outer.Inner inner = new Outer.Inner();
            //静态内部类,只能方位外部类的静态成员
            inner.show();
        }
    }
    
    //创建外部类
    class Outer {
        private static int age = 19;
        private String name = "张三";
        //创建静态内部类
        public static class Inner {
            public void show() {
                System.out.println(age);
            }
        }
    }
(3)局部内部类

是定义在方法中,代码中,构造器等执行中

(4)匿名内部类
  • 作用 :更方便的创建一个子类对象(简化操作类、接口的代码)
  • 格式 :

new 类名/接口名(参数值){

一般都是方法重写;

};

  • 特点:本质是一个子类对象, 编译器会帮我们创建一个子类的对象
    public class Demo {
    
        public static void main(String[] args) {
            //需求1: 创建Animal的子类对象,并调用方法
            Animal a1 = new Dog();
            a1.eat();
            //需求2: 创建Bird的实现类对象,并调用方法
            Bird b1 = new Crow();
            b1.drink();
            //需求3: 创建Animal的子类对象,并调用方法(匿名内部类实现)
            Animal a2 = new Animal() {
                @Override
                public void eat() {
                    System.out.println("吃肉吃肉");
                }
            };
            a2.eat();
    
            //需求4: 创建Bird的实现类对象,并调用方法(匿名内部类实现)
            Bird b2 = new Bird() {
                @Override
                public void drink() {
                    System.out.println("喝水喝水");
    
                }
            };
            b2.drink();
    
        }
    }
    
    //抽象类
    abstract class Animal {
        public abstract void eat();
    }
    
    //接口(Bird 鸟   Crow 乌鸦)
    interface Bird {
        void drink();
    }
    class Crow implements Bird {
        @Override
        public void drink() {
            System.out.println("乌鸦喝水");
        }
    }
    (5)匿名内部类应用 
  • 匿名内部类应用场景------作为方法的参数进行传递 如果一个方法将一个抽象类/接口最为参数,那我们可以直接传递该抽象类/接口的匿名内部类对象
    public class Demo {
    
        public static void main(String[] args) {
            //需求1: 调用test1方法,传入一个Animal的子类, 打印出 狗在吃肉
            test1(new Animal() {
                @Override
                public void eat() {
                    System.out.println("狗在吃肉");
                }
            });
            //需求2: 调用test2方法,传入一个bird的实现类, 打印出 乌鸦在喝水
            test2(new Bird() {
                @Override
                public void drink() {
                    System.out.println("乌鸦在喝水");
                }
            });
        }
    
        public static void test1(Animal animal) {
            animal.eat();
        }
    
        public static void test2(Bird bird) {
            bird.drink();
        }
    
    }
    
    //抽象类
    abstract class Animal {
        public abstract void eat();
    }
    
    //接口
    interface Bird {
        void drink();
    }

    二.泛型

(1)认识泛型
  • 定义: 定义类、接口、方法时,同时声明的类型变量(如:<E>) ,称为泛型。
  • 作用 :泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力! 这样可以避免强制类型转换,及其可能出现的异常。
  • 本质:把具体的数据类型作为参数传给类型变量
  • 分类:泛型类、泛型接口、泛型方法
  • public class Demo {
        public static void main(String[] args) {
            //需求1. 定义一个ArrayList不设置泛型, 保存元素, 然后遍历求元素的长度
    //        ArrayList list1 = new ArrayList();
    //        list1.add("关羽");
    //        list1.add("张飞");
    //        list1.add(1234);
    //        list1.add(true);
    //        for (int i = 0; i < list1.size(); i++) {
    //            //多态
    //            Object obj = list1.get(i);
    //            //强转
    //            String str = (String) obj;
    //            //元素的长度
    //            System.out.println(str.length());
    //        }
    
            //需求2. 定义一个ArrayList, 设置泛型为String, 保存数据, 然后遍历求元素的长度
            ArrayList<String> list2 = new ArrayList<String>();
            list2.add("关羽");
            list2.add("张飞");
            list2.add("1234");
            for (int i = 0; i < list2.size(); i++) {
                String str = list2.get(i);
                System.out.println(str.length());
            }
        }
    }
    
    (2)泛型类
  • 在定义类的时候设置泛型, 然后在后续方法上使用
  • 格式 修饰符 class 类名<类型变量,类型变量,…> {

}

  • 注意: 类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
public class Demo {
    public static void main(String[] args) {
        //1、创建MyList对象
        MyList<String> list = new MyList<>();
        //2、向MyList中存放数据
        list.add("张飞");
        System.out.println(list.get(0));
    }
}

//自定义一个泛型类, 模仿ArrayList的add和get功能,只能存放10条数据
class MyList<E> {
    //1、定义一个长度为10的数组
    private Object [] arr = new Object[10];

    //2、定一个当前存放元素的索引位置
    private int index = 0;

    //方法1:添加元素
    public void add (E e) {
        arr[index] = e;
        //索引加+1
        index ++ ;
    }


    //方法2:根据索引查询元素并返回
    public E get(int index) {
        return (E) arr[index];
    }
}
(3)泛型接口
  • 在定义接口的时候声明泛型
  • 格式:修饰符 interface 类名<类型变量,类型变量,…> {

}

  • 注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
  • public class Demo {
        public static void main(String[] args) {
            CommmonInterface ci = new TeacherInterfaceImpl();
            ci.findByName("zhangsan");
        }
    }
    
    //需求: 定义一个接口(接口中拥有两个功能: 保存对象数据和根据名称返回对象)
    //谁实现这个接口,谁就需要对两个功能做就提实现
    interface CommmonInterface<E> {
        void add(E e);
        E findByName(String name);
    }
    
    //实现公共的泛型接口,并设置数据类型
    class TeacherInterfaceImpl implements CommmonInterface<Teacher>{
        @Override
        public void add(Teacher teacher) {
    
        }
    
        @Override
        public Teacher findByName(String name) {
            System.out.println("根据name查询老师:" + name);
            return null;
        }
    }
    
    
    class StudentInterfaceImpl implements CommmonInterface<Student>{
        @Override
        public void add(Student student) {
        }
    
        @Override
        public Student findByName(String name) {
            return null;
        }
    }
(4)泛型方法
  • 修饰符<类型变量1, 类型交最2> 返回值类型 方法名(参数列表){

}

  • 注意: 类型变量建议使用大写的英文宁母,常见为E、T、K、V等
  • public class Demo {
    
        public static void main(String[] args) {
            //需求1: 调用test1方法,传入一个Animal的子类, 打印出 狗在吃肉
            test1(new Animal() {
                @Override
                public void eat() {
                    System.out.println("狗在吃肉");
                }
            });
            //需求2: 调用test2方法,传入一个bird的实现类, 打印出 乌鸦在喝水
            test2(new Bird() {
                @Override
                public void drink() {
                    System.out.println("乌鸦在喝水");
                }
            });
        }
    
        public static void test1(Animal animal) {
            animal.eat();
        }
    
        public static void test2(Bird bird) {
            bird.drink();
        }
    
    }
    
    //抽象类
    abstract class Animal {
        public abstract void eat();
    }
    
    //接口
    interface Bird {
        void drink();
    }
(5)泛型通配符
  • 通配符 <?>,可以在使用泛型的时候,代表一切类型
  • 泛型上限 <?extends 类名>,能接收指定类型利子类
  • 泛型下限 <?super类名>,接收指定类型和父类
  • public class Demo {
        public static void main(String[] args) {
            //数据准备
            ArrayList<Animal> animals = new ArrayList();
            ArrayList<Dog> dogs = new ArrayList<Dog>();
            ArrayList<Person> persons = new ArrayList<Person>();
            ArrayList<Teacher> teachers = new ArrayList<Teacher>();
            ArrayList<Student> students = new ArrayList<Student>();
    
            //--------------需求1--------------------
            m1(animals);
            m1(dogs);
            m1(persons);
            m1(teachers);
            m1(students);
    
            //---------------需求2-------------------
            //m2(animals);
            //m2(dogs);
            m2(persons);
            m2(teachers);
            m2(students);
    
            //---------------需求3-------------------
            m3(animals);
            //m3(dogs);
            m3(persons);
            //m3(teachers);
            //m3(students);
        }
    
        //需求1: 定义一个方法m1,参数为一个ArrayList集合,集合中可以存放任意类型的参数
        public static void m1(ArrayList<?> list) {
            System.out.println(list.size());
        }
    
        //需求2: 定义一个方法m2,参数为一个ArrayList集合,集合中可以存放Person及其子类型的参数
        public static void m2(ArrayList< ? extends Person> list) {
            System.out.println(list.size());
        }
    
        //需求3: 定义一个方法m3,参数为一个ArrayList集合,集合中可以存放Person及其父类型的参数
        public static void m3(ArrayList< ? super Person> list) {
            System.out.println(list.size());
        }
    }
    
    
    
    
    
    //动物
    class Animal{
    
    }
    //狗
    class Dog extends Animal{
    
    }
    //人
    class Person extends Animal{
    
    }
    //老师
    class Teacher extends Person{
    
    }
    //学生
    class Student extends Person{
    
    }
    
(6)注意事项
  1. 一旦将java文件编译为class文件,泛型就不存在了,称为泛型擦除
  2. 泛型不支持基本数据类型,只支持引用类型(存基本类型呢?后面学包装类)
public class Demo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList();
        list.add(1);

        //包装类,将基本数据类型处理,转化为引用类型
    }
}

class MyList<E> {
    private Object[] arr = new Object[10];
    private int size;

    //添加方法
    public void add(E e) {
        arr[size++] = e;
    }

    //获取方法
    public E get(int index) {
        return (E) arr[index];
    }
}

三.api

(1)常量
  • 命名规范: 单词全部大写,多个之间使用_连接
  • 优点: 1. 代码可读性更好,可维护性也更好。 2. 程序编译后,出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
public class Demo {
    public static void main(String[] args) {
        System.out.println("学校名称:" + Constant.SCHOOL_NAME);
        //需求2: 保存学生的性别, 为提高性能,经常使用0和1表示性别
        System.out.println(Constant.MALE);
    }
}

//需求1: 定义一个常量,记录学校的名称
class Constant {
    //记录所有的常量信息(状态,系统的配置)
    public static final String SCHOOL_NAME="黑马程序员";
    //性别
    public static final int MALE = 0; //男
    public static final int FEMALE = 1; //女
}
(2)枚举
  • Java提供的一种用于简洁表示一些固定值的类
  • 枚举类格式 :修饰符 enum 校举类名{ 校举顶1,校举项2..; 其他成员.. }
  • 枚举的特点:

1、枚举类的第一行只能罗列一些名称,且默认都是常量,每个常量记住的就是枚举类的一个对象 2、枚举类的构造器都是私有的(自己提供也只能是私有的),因此枚举类对外不能创建对象

3、枚举都是最终类,不能被继承

4、枚举类中,从第二行开始,可以定义类的其他成员

5、编译器为枚举类新增了几个方法,并且所有校举类都是java.lang.Enum的子类,所以可以使用父类的方法

public class Demo {
    public static void main(String[] args) {
        //1. 需求: 创建Student对象,使用set赋值为:张三,MAN
        Student student = new Student();
        student.setName("张三");
        student.setSex(Sex.FEMALE);
        System.out.println(student);
    }
}

//定义枚举类
enum Sex {
    MALE,FEMALE;
}

class Student {
    private String name;
    private Sex sex; //使用枚举表示性别

    public void setSex(Sex sex) {
        this.sex = sex;
    }

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

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

(3)object
  • Object类是Java中所有类的祖宗类,类中的方法可以被所有Java类所使用
  • String toString(): 返回对象的字符串表示形式, 默认打印对象的内存地址, 一般用于子类重写返回对象的指定格式
  • boolean equals(Object o): 判断两个对象是否相等, 默认比较两个对象的内存地址, 一般用于子类重写自定义比较规则
  • public class Demo {
        public static void main(String[] args) {
            //创建student1
            Student student1 = new Student("张三",18);
            System.out.println(student1.toString());
    
            System.out.println("-----------------");
            //创建student2
            Student student2 = new Student("张三",18);
            System.out.println(student2.toString());
    
            System.out.println("-----------------");
            //比较student1和student2
            boolean equals = student1.equals(student2);
            System.out.println("两个对象是否相等:" + equals); //false
        }
    }
    
    class Student {
        String name;
        int age;
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age && Objects.equals(name, student.name);
        }
    
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

Object类常用方法 protected object clone() 对象克隆

  • 浅克隆: 将基本类型数值、引用类型的地址都拷贝一份

1、子类必须实现cloneable接口(标记接口),否则运行报CloneNotSupportedException

2、子类重写clone方法, 在里面直接调用父类提供的clone方法

  • 深克降: 将基本类型数值、字符串的地址都拷贝一份; 其他引用类型的数据,会创建新对象完成拷贝(拷贝出新的地址)

1、子类必须实现cloneable接口(标记接口),否则运行报CloneNotSupportedException

2、子类重写clone方法, 在里面直接调用父类提供的clone方法

3、在clone方法中, 将克隆得到的对象中的引用类型重新手动clone一下再复制到对象中

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        //1. 创建学生对象
        Student student = new Student(1, "张三", "admin", new double[]{20, 30, 50});
        System.out.println(student);
        System.out.println(student.id);
        System.out.println(student.username);
        System.out.println(student.password);
        System.out.println(student.scores);

        //2. 克隆一个学生对象
        System.out.println("=====================克隆对象=============================");

        Student cloneStudent = (Student)student.clone();
        System.out.println(cloneStudent);
        System.out.println(cloneStudent.id);
        System.out.println(cloneStudent.username);
        System.out.println(cloneStudent.password);
        System.out.println(cloneStudent.scores);


        //修改原始数据
        student.scores[0] = 99;
        //打印克隆后对象
        System.out.println(cloneStudent.scores[0]);
    }
}

//CloneNotSupportedException : 不支持克隆

/**
 * 1、java类实现空接口Cloneable
 * 2、重写父类clone方法
 */
class Student implements Cloneable{
    int id;
    String username;
    String password;
    double[] scores;

    public Student(int id, String username, String password, double[] scores) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.scores = scores;
    }

    //重写父类的clone
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //1、调用父类的克隆方法,创建一个浅克隆对象
        Student student = (Student) super.clone();
        //2、对浅克隆对象中存在地址问题的引用类型数据,重新赋值
        student.scores = student.scores.clone();
        //3、返回
        return student;
        //return super.clone();
    }
}
(4)objects

java提供的一个工具类

常见方法

  • public static boolean equals(Object a, Object b); 先做非空判断,再比较两个参数是否相等 (更严谨安全,避免空指针)
  • public static boolean isNull(Object o); 判断对象是否为null,是返回true
  • public static boolean nonNull(Object o); 判断对象是否不为null,是返回true */
  • public class Demo {
        public static void main(String[] args) {
            //1. 定义两个字符串对象
            String s1 = null;   //NullPointerException 空指针异常:使用一个空对象中的方法或者属性
            String s2 = "itheima";
    
            //2. 判断两个对象是否相等
            //boolean equals = s1.equals(s2);
            boolean equals = Objects.equals(s1, s2);
            System.out.println(equals);
    
            //3. 判断对象是否为空
            boolean aNull = Objects.isNull(s1);
            System.out.println(aNull); //true
    
            //4. 判断对象是否不为空
            boolean nonNull = Objects.nonNull(s1);
            System.out.println(nonNull); //true
        }
    }
    
(5)包装类

为了更好的支持面向对象, java为每一种基本类型都提供了一种对应的包装类型

具体

byte-->Byte short-->Short long-->Long float-->Float double-->Double boolean-->Boolean int-->Integer char-->Character

下面以Integer的角度学习, 其它都是类似的

  • 创建对象

Integer(int value/String value) 构造方法(过时),接收int或string封装成Integer对象

static Integer valueOf(int i/String value) 替代构造方法,接收int或string封装成Integer对象

  • 拆箱和装箱(基本类型和包装类的相互转换)
  1. 自动装箱: java支将基本类型直接值给对应包装类,底层使用的是valueOf()方法
  2. 自动拆箱: java支持将包装类直接赋值给对应基本类型,底层调intValue()方法
  • 跟字符串的互相转换

static String toString(int i) 将Integer象封装的数值转为String类型

static int parseInt(String s) 将字符串数值转为int数值

static Integer Integer.valueOf(str) 将字符串转化成包装类 

public class Demo {
    public static void main(String[] args) {


        //1. 创建对象
        Integer in1 = new Integer(5);
        System.out.println(in1);
        Integer in2 = Integer.valueOf(10);
        System.out.println(in2);
        //2. 拆箱和装箱
        Integer in3 = 8;  //装箱:将基本类型的数据自动转化为包装类型
        int tem = in3;    //拆箱:将包装类型转化为基本类型数据
        //3.跟字符串的互相转换
        String string = in3.toString();
        System.out.println(string);

        
        String str = "100";
        Integer in4 = Integer.valueOf(str);
        System.out.println(in4);

        int tem2 = Integer.parseInt(str);
        System.out.println("tem2=" +tem2);
    }
}

//面试题: 输出下面代码的执行原理
//Integer x = 100; //装箱
//x += 200;   //先拆箱,再装箱    x = x + 200
//System.out.println(x);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值