了解内部类&泛型&常用API

内部类

一个类嵌套在另一个类内部就叫内部类

匿名内部类 

本质上是一个没有名字的子类对象、或者接口的实现类对象 

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

    作用:

           简化了创建子类对象、实现类对象的书写格式 

/*
匿名内部类应用场景------作为方法的参数进行传递
    如果一个方法将一个抽象类/接口最为参数,那我们可以直接传递该抽象类/接口的匿名内部类对象

*/
public class Demo {

    public static void main(String[] args) {
        //需求1: 调用test1方法, 打印出 狗在吃肉

        test1(new Animal() {
            @Override
            public void eat() {
                System.out.println("DOG在吃肉");
            }
        });
        //需求2: 调用test2方法, 打印出 乌鸦在喝水

        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.泛型就是在类定义时不明确类型,在使用时明确类型

 2.基本类型不能保存到泛型中,必须使用包装类

 3. 泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!

 这样可以避免强制类型转换,及其可能出现的异常

 4.泛型只在编译期有效,编译后会擦除

 5.泛型只支持引用类型

泛型类 

//需求2. 定义一个ArrayList, 设置泛型为String, 保存数据, 然后遍历求元素的长度

        ArrayList<String> strings = new ArrayList<>();
        strings.add("nihao");
        strings.add("haha");
        for (int i = 0; i < strings.size(); i++) {
            System.out.println(strings.get(i));
        }
public class MyPoint <T>{
 
    //此时X的类型不确定,在产生这个对象时确定类型
    private T x;
    private T y;
 
    public T getX() {
        return x;
    }
 
    public void setX(T x) {
        this.x = x;
    }
 
    public T getY() {
        return y;
    }
 
    public void setY(T y) {
        this.y = y;
    }
 
    public static void main(String[] args) {
        MyPoint<String> myPoint = new MyPoint<>();
        //类型不一致报错
        myPoint.setY(10);
        myPoint.setX("北纬20度");
        System.out.println(myPoint.getX());
    }
}
public class MypointNew <T,E>{
 
    private T x;
    private E y;
 
    public T getX() {
        return x;
    }
 
    public void setX(T x) {
        this.x = x;
    }
 
    public E getY() {
        return y;
    }
 
    public void setY(E y) {
        this.y = y;
    }
 
    public static void main(String[] args) {
        MypointNew<String,Integer> mypointNew = new MypointNew<>();
        mypointNew.setX("hello");
        mypointNew.setY(10);
    }
}

泛型接口 

/*
泛型接口
    在定义接口的时候声明泛型

格式
    修饰符 interface 类名<类型变量,类型变量,…> {

    }

注意
    类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
*/
public class Demo {
    public static void main(String[] args) {

    }
}

//需求: 定义一个接口(接口中拥有两个功能: 保存对象数据和根据名称返回对象)
//谁实现这个接口,谁就需要对两个功能做就提实现

interface Common<T>{
    void add(T e);//保存
    T findByName(String name);//查询
}

class Teacher implements Common<Teacher>{


    @Override
    public void add(Teacher e) {

    }

    @Override
    public Teacher findByName(String name) {
        return null;
    }
}


//interface StudentInterface{
//    void add(Student student);//保存
//    Student findByName(String name);//查询
//}

class Student implements Common<Student>{

    @Override
    public void add(Student e) {

    }

    @Override
    public Student findByName(String name) {
        return null;
    }
}

泛型方法 

//需求: 编写一个将两个相同类型的对象放入一个集合的方法
        ArrayList<Teacher> list1 = add(new Teacher(), new Teacher());
//        ArrayList<String> list2 = add("1", "2");
//        ArrayList<String> list3 = add("1", "2");

    }

    //将两个字符串放入一个集合  
//    public static ArrayList<String> add(String a, String b) {
//        ArrayList<String> arrayList = new ArrayList<>();
//        arrayList.add(a);
//        arrayList.add(b);
//        return arrayList;
//    }

   // 将两个Teacher放入一个集合  泛型方法!!!
    public static <T> ArrayList<T> add(T a, T b) {
        ArrayList<T> arrayList = new ArrayList<>();
        arrayList.add(a);
        arrayList.add(b);
        return arrayList;
    }
//
//    //将两个Student放入一个集合
//    public static ArrayList<Student> add(Student a, Student b) {
//        ArrayList<Student> arrayList = new ArrayList<>();
//        arrayList.add(a);
//        arrayList.add(b);
//        return arrayList;
//    }

}
//不是泛型方法
public  E  get(int i){
    return (E)objects[i];
}

 //泛型方法

 public static <T> void test ( T  t ) {  

  }

泛型通配符 

 <?> :表示任意类型

 <? extends Car> :? 能接收的必须是Car或者其子类

 <?  super    Car> : ?  能接收的必须是Car或者其父类

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>();

        m2(persons);
        m2(teachers);

        m3(persons);
        m3(animals);
    }

    //需求1: 定义一个方法m1,参数为一个ArrayList集合,集合中可以存放任意类型的参数

     public static void m1(ArrayList<?> arrayList){

     }
    //需求2: 定义一个方法m2,参数为一个ArrayList集合,集合中可以存放Person及其子类型的参数

    public static void m2(ArrayList< ? extends Person>  arrayLists){

    }
    //需求3: 定义一个方法m3,参数为一个ArrayList集合,集合中可以存放Person及其父类型的参数

    public static void m3(ArrayList< ? super Person > p){

    }

}

//动物
class Animal{

}
//狗
class Dog extends Animal{

}
//人
class Person extends Animal{

}
//老师
class Teacher extends Person{

}
//学生
class Student extends Person{

}

Object 

      Object类是Java中所有类的祖宗类,因此,Java中所有类的对象都可以直接使用Object类中提供的一些方法。 

Object中toString方法的作用是什么?存在的意义是什么?

基本作用:返回对象的字符串形式。

存在的意义:让子类重写,以便返回子类对象的内容。 

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

Object中equals方法的作用是什么?存在的意义是什么?

基本作用:默认是比较两个对象的地址是否相等。

存在的意义:让子类重写,以便用于比较对象的内容是否相同。 

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

浅克隆与深克隆 

浅克隆 

拷贝出的新对象,与原对象中的数据一模一样(引用类型拷贝的只是地址) 

浅克隆: 将基本类型数值、引用类型的地址都拷贝一份
    1、子类必须实现cloneable接口(标记接口),否则运行报CloneNotSupportedException
    2、子类重写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);
    }
}


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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

浅克隆运行结果:

com.itheima.l_api_object2.Student@7b65de14
1
张三
admin
[D@3429dbb8
=====================克隆对象=============================
com.itheima.l_api_object2.Student@3942ef25
1
张三
admin
[D@3429dbb8

深克隆 

1.对象中基本类型的数据直接拷贝。

2.对象中的字符串数据拷贝的还是地址。

3.对象中还包含的其他对象,不会拷贝地址,会创建新对象。 

深克隆: 将基本类型数值、字符串的地址都拷贝一份; 其他引用类型的数据,会创建新对象完成拷贝(拷贝出新的地址)
    1、子类必须实现cloneable接口(标记接口),否则运行报CloneNotSupportedException
    2、子类重写clone方法, 在里面直接调用父类提供的clone方法
    3、在clone方法中, 将克隆得到的对象中的引用类型重新手动clone一下再复制到对象中

    @Override
    protected Object clone() throws CloneNotSupportedException {

       // return super.clone(); 调用父类克隆方法,克隆出对象

        //3、在clone方法中, 将克隆得到的对象中的引用类型重新手动clone一下再复制到对象中
        Student cloneStudent = (Student)super.clone();
        cloneStudent.scores = cloneStudent.scores.clone();
        return cloneStudent;
    }

Objects 

public class Demo {
    public static void main(String[] args) {
        //1. 定义两个字符串对象
        String s1 = null;
        String s2 = "itheima";

        //2. 判断两个对象是否相等
        //避免了空指针异常
        System.out.println(Objects.equals(s1,s2));//false
        //3. 判断对象是否为空
        System.out.println(Objects.isNull(s1));//true
        //4. 判断对象是否不为空
        System.out.println(Objects.nonNull(s1));//false
    }
}

包装类 

为什么要有包装类:

为了万物皆对象,并且泛型和集合都不支持基本类型,支持包装类 8种,int -> Integer ,   char -> Character,其他的都是首字母大写 

包装类常用功能

自动装箱 

java支将基本类型直接值给对应包装类,底层使用的是valueOf()方法 

Integer c = Integer.valueOf(10);//底层
Integer e = 10;//Integer.valueOf(10);

自动拆箱 

java支持将包装类直接赋值给对应基本类型,底层调intValue()方法 

int f = e;//e.intValue()

面试题:说出下面代码的执行原理 

        Integer x = 100;//装箱
        x += 200;//x-->拆箱int   int+=200   --->x  装箱 
        System.out.println(x);

跟字符串互换 

        String s = Integer.toString(100);
        String s1 = 100 + "";
        //static int parseInt(String s) 将字符串数值转为int数值
        int i = Integer.parseInt("100");

 String与StringBuilder与StringBuffer

 String链接:JDK常用接口和String类_IT_Rocter的博客-CSDN博客

 StringBuilder

 1.StringBuilder代表可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,就是用来操作字符串的

 2.StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁

public class Demo1 {
    public static void main(String[] args) {
        //1. 创建StringBuilder
        StringBuilder sb = new StringBuilder();
        StringBuilder sb1 = new StringBuilder("abc");
        System.out.println(sb);
        System.out.println(sb1);
        //2. 字符拼接
        System.out.println(sb1.append("d").append("E"));
        //3. 反转内容
        System.out.println(sb1.reverse());
        //4. 返回长度
        System.out.println(sb1.length());
        //5. 转为字符串
        System.out.println(sb1.toString());
    }

}
/*
    设计一个方法,用于返回任意整型数组的内容,要求返回的数组内容格式如:[11,22,33]
*/
public class Demo2 {

    public static void main(String[] args) {
        //定义数组
        int[] arr = {11, 22, 33};
        System.out.println(print(arr));
    }

    //需求1: 使用String搞

    public static String print(int[] arr){

        String a  = "[";

        for (int i = 0; i < arr.length; i++) {

            if( i != arr.length - 1){
                a += arr[i] + ",";
            }else {
                a += arr[i] + "]";
            }

        }

        return a;
    }
    //需求2: 使用StringBuilder搞

    public static String print2(int arr[]){

        StringBuilder sb = new StringBuilder("[");

        for (int i = 0; i < arr.length; i++) {
            if (i != arr.length - 1) {
                sb.append(arr[i]).append(",");
            } else {
                sb.append(arr[i]);
            }
        }
        //3. 拼上结束符号
        sb.append("]");
        //4. 返回
        return sb.toString();
    }
}

1.对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuidler,效率更高! 

2.注意:如果操作字符串较少,或者不需要操作,以及定义字符串变量,还是建议用String。

StringBuffer

1.StringBuffer的用法与StringBuilder是一模一样的

2.但StringBuilder是线程不安全的  StringBuffer是线程安全的 

StringJoiner 

1.JDK8开始才有的,跟StringBuilder一样,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的。

2.好处:不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁 

public class Demo {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33};
        System.out.println(print(arr));
    }

    //需求: 设计一个方法,按照格式要求,返回任意类型数组内容
    public static String print(int[] arr) {
        //1. 创建StringJoiner可以直接指定开始 分隔 结束符号
        StringJoiner stringJoiner = new StringJoiner(",", "[", "]");

        //2. 遍历数组获取元素
        for (int i = 0; i < arr.length; i++) {
            stringJoiner.add(arr[i] + "");
        }

        //3. 转化为String返回
        return stringJoiner.toString();
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值