内部类
一个类嵌套在另一个类内部就叫内部类
匿名内部类
本质上是一个没有名字的子类对象、或者接口的实现类对象
通常作为一个参数传输给方法
作用:
简化了创建子类对象、实现类对象的书写格式
/*
匿名内部类应用场景------作为方法的参数进行传递
如果一个方法将一个抽象类/接口最为参数,那我们可以直接传递该抽象类/接口的匿名内部类对象
*/
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();
}
}