1. 内部类
1.1 内部类的概述
内部类
内部类是类中的五大成分之一(成员变量、方法、构造器、代码块、
内部类
)
如果一个类定义在另一个类的内部,这个类就是内部类。
场景:
当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。
定义格式:
1.2 内部类分为四种
成员内部类[了解]:位于一个类里面成员位置的类
静态内部类[了解]:使用
static
修饰的成员内部类
局部内部类[了解]:在方法里面定义的类
匿名内部类[重点]:一种特殊的局部内部类
成员内部类
静态内部类
局部内部类
局部内部类是定义在方法中、代码块中、构造器等执行体中 (用到的不多,前三个大多是了解)
匿名内部类
这是一种特殊的局部内部类
所谓匿名:指的是程序员不需要为这个类声明名字
作用:更方便的创建一个子类对象(简化操作类、接口的代码)
本质:匿名内部类本质就是一个子类,并会立即创建出一个子类对象
场景: 通常作为一个参数传输给方法
/*
匿名内部类应用场景------作为方法的参数进行传递
如果一个方法将一个抽象类/接口最为参数,那我们可以直接传递该抽象类/接口的匿名内部类对象
*/
public class Demo {
public static void main(String[] args) {
//需求1: 调用test1方法, 打印出 狗在吃肉
test1(new Animal() {
@Override
public void eat() {
System.out.println("狗吃大刀肉");
}
});
//需求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();
}
2. 泛型
2.1 泛型
定义类、接口、方法时,同时声明的类型变量(如:<E>) ,称为泛型。
/*
泛型
定义
定义类、接口、方法时,同时声明的类型变量(如:<E>) ,称为泛型。
作用
泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!
这样可以避免强制类型转换,及其可能出现的异常。
本质
把具体的数据类型作为参数传给类型变量
分类
泛型类、泛型接口、泛型方法
*/
public class Demo {
public static void main(String[] args) {
//需求1. 定义一个ArrayList不设置泛型, 保存元素, 然后遍历求元素的长度
ArrayList list1 = new ArrayList();
list1.add("关羽");
list1.add(12.12);
list1.add(1234);
list1.add(true);
for (int i = 0; i < list1.size(); i++) {
Object object = list1.get(i);
String str = (String) object;
}
//需求2. 定义一个ArrayList, 设置泛型为String, 保存数据, 然后遍历求元素的长度
ArrayList<String> list2 = new ArrayList<>();
list2.add("张飞");
list2.add("典韦");
// list2.add(123);会报错
for (int i = 0; i < list2.size(); i++) {
System.out.println(list1.get(i));
}
}
}
2.2泛型类
/*
泛型类
在定义类的时候设置泛型, 然后在后续方法上使用
格式
修饰符 class 类名<类型变量,类型变量,…> {
}
注意:
类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
*/
public class Demo {
public static void main(String[] args) {
MyList<String> myList = new MyList();
myList.add("123");
myList.add("关羽");
}
}
//自定义一个泛型类, 模仿ArrayList的add和get功能
class MyList<E> {
//1.定义一个长度为10的数组
private E[] arr =(E[]) new Object[10];
//2.定义一个存放元素的索引
private int index = 0;
//方法1:添加元素
public void add(E e) {
arr[index] = e;
//索引加一
index++;
}
public E get(int index) {
return arr[index];
}
}
2.3泛型接口
//需要自己创建两个类(学生,老师)
/*
泛型接口
在定义接口的时候声明泛型
格式
修饰符 interface 类名<类型变量,类型变量,…> {
}
注意
类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
*/
public class Demo {
public static void main(String[] args) {
CommonInterface c1 = new TeacherInterfaceImpl();
c1.findByName("老张");
}
}
//需求: 定义一个接口(接口中拥有两个功能: 保存对象数据和根据名称返回对象)
//谁实现这个接口,谁就需要对两个功能做就提实现
interface CommonInterface<E>{
void add(E e);
E findByName(String name);
}
interface TeacherInterface{
void add(Teacher teacher);//保存
Teacher findByName(String name);//查询
}
class TeacherInterfaceImpl implements CommonInterface<Teacher>{
@Override
public void add(Teacher teacher) {
}
@Override
public Teacher findByName(String name) {
System.out.println("老张");
return null;
}
}
interface StudentInterface{
void add(Student student);//保存
Student findByName(String name);//查询
}
class StudentInterfaceImpl implements CommonInterface<Student>{
@Override
public void add(Student student) {
}
@Override
public Student findByName(String name) {
return null;
}
}
2.4泛型接口
泛型方法中格式是接收所有类型,实际应用中会限制他的类型,用来约束传过来的的参数,这样就起到了泛型的作用。
public class Demo {
public static void main(String[] args) {
//需求: 编写一个将两个相同类型的对象放入一个集合的方法
ArrayList<String> list1 = add("1", "2");
Teacher t1 = new Teacher("1");
Teacher t2 = new Teacher("2");
ArrayList<Teacher> list2 = add(t1, t2);//Teacher类
Student s1 = new Student("1");
Student s2 = new Student("2");
ArrayList<Student> list3 = add(s1, s2);//Student类
}
public static <E> ArrayList<E> add(E a, E b) {
ArrayList<E> list = new ArrayList<>();
list.add(a);
list.add(b);
return list;
}
//将两个字符串放入一个集合
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 ArrayList<Teacher> add(Teacher a, Teacher b) {
ArrayList<Teacher> 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;
}
}
class Teacher {
private String name;
public Teacher(String name) {
name = name;
}
}
class Student {
private String name;
public Student(String name) {
name = name;
}
}
2.4泛型通配符、上下限
方法中可以写成T extends 类名,这样可以限制传输过来的类的类型(作业当中会用到)
/*
通配符
<?>,可以在使用泛型的时候,代表一切类型
泛型上限
<?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{
}
2.4泛型的擦除问题和注意事项
3. 常用API
3.1 常量
/*
常量:
使用了static final修饰的成员变量就被称为常量, 通常用于记录系统的配置信息。
命名规范:
单词全部大写,多个之间使用_连接
优点:
1. 代码可读性更好,可维护性也更好。
2. 程序编译后,出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
*/
public class Demo {
public static void main(String[] args) {
System.out.println(Constant.STUDENT_NAME);
// Constant.STUDENT_NAME = "新加坡";//Cannot assign a value to final variable 'STUDENT_NAME' 不能被修改
//需求2: 保存学生的性别, 为提高性能,经常使用0和1表示性别
System.out.println(Constant.STUDENT_MALE);
}
}
//需求1: 定义一个常量,记录学校的名称
class Constant {
public static final String STUDENT_NAME = "马家堡";
public static final int STUDENT_MALE = 0;
public static final int STUDENT_FEMALE = 1;
}
3.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.MALE);//java: 不兼容的类型: java.lang.String无法转换为枚举.Sex
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.2 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);
//打印student1默认就是用toString,打印的是student1的地址值,我们要输出他的内容需重写toString()
System.out.println(student1.toString());//Student{name='老张', age=18}
System.out.println("————————————————");
Student student2 = new Student("老张", 18);
System.out.println(student2);//Student{name='老张', age=18}
System.out.println("————————————————");
//equals()默认比较的是两个对象的地址值,我们判断他的内容是否相等需重写equals
boolean equals = student1.equals(student2);
System.out.println("两个对象是否相等:" + equals);//两个对象是否相等:true (重写完之后比较的就是内容)
}
}
class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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);
}
}
浅克隆
/*
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);//Student@4eec7777
System.out.println(student.id);
System.out.println(student.username);
System.out.println(student.password);
System.out.println(student.scores);//[D@3b07d329
//2. 克隆一个学生对象
System.out.println("=====================克隆对象=============================");
Student cloneStudent = (Student)student.clone();
System.out.println(cloneStudent);//Student@41629346
System.out.println(cloneStudent.id);
System.out.println(cloneStudent.username);
System.out.println(cloneStudent.password);
System.out.println(cloneStudent.scores);//[D@3b07d329
}
}
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();
}
}
深克隆
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);//Student@4eec7777
System.out.println(student.id);
System.out.println(student.username);
System.out.println(student.password);
System.out.println(student.scores);//[D@3b07d329
//2. 克隆一个学生对象
System.out.println("=====================克隆对象=============================");
Student cloneStudent = (Student)student.clone();
System.out.println(cloneStudent);//Student@41629346
System.out.println(cloneStudent.id);
System.out.println(cloneStudent.username);
System.out.println(cloneStudent.password);
System.out.println(cloneStudent.scores);//浅克隆:[D@3b07d329//深克隆:[D@404b9385
}
}
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 {
//1.调用父类的克隆方法,创建一个浅克隆对象
Student clone = (Student) super.clone();
//2.对浅克隆对象中存在地址问题的引用类型数据,重新赋值
clone.scores = clone.scores.clone();
//3.返回对象
return clone;
}
}
3.3 Objects类
3.4 包装类