内部类
-
内部类是类中的五大成分之一(成员变量、方法、构造器、代码块、内部类)
-
如果一个类定义在另一个类的内部,这个类就是内部类。
-
场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。
-
public class Car{ // 内部类 public class Engine{ } }
成员内部类
是定义在一个类中成员位置的类,在内部类中也可以定义成员属性和方法
public class Outer {
// 成员内部类
public class Inner {
// 成员属性和方法
}
}
创建对象的格式
外部类名.内部类名 对象名 = new 外部类(...).new 内部类(...);
Outer.Inner in = new Outer().new Inner();
- 成员内部类中访问其他成员的特点:
- 成员内部类中可以定义实例成员,静态成员 (注意: 静态成员从JDK16开始支持)
- 成员内部类中的实例方法中,可以直接访问外部类的实例成员,静态成员
- 如果内部类和外部类出现了重名的成员,可以通过(外部类名.this.xxx) 强行访问外部类的成员
成员内部类的访问拓展:
- 成员内部类中是否可以直接访问外部类的静态成员?
- 可以,外部类的静态成员只有一份可以被共享访问。
- 成员内部类的实例方法中是否可以直接访问外部类的实例成员?
- 可以的,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员。
总结
- 成员内部类是什么样的、有什么特点?
- 无static修饰,属于外部类的对象。
- 可以直接访问外部类的静态成员,实例方法中可以直接访问外部类的实例成员。
- 成员内部类如何创建对象?
- 外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器();
静态内部类
使用static修饰的成员内部类
public class Outer{
// 静态内部类
public static class Inner{
}
}
创建对象的格式:
外部类名.内部类名 对象名 = new 外部类.内部类(…);Outer.Inner in = new Outer.Inner();
静态内部类中访问外部类成员的特点
可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。
+ 静态内部类的使用场景、特点、访问总结。
+ 如果一个类中包含了一个完整的成分,如汽车类中的发动机类。
+ 特点、使用与普通类是一样的,类有的成分它都有,只是位置在别人里面而已。
+ 访问总结:可以直接访问外部类的静态成员,不能直接访问外部类的实例成员。
+ 注意:开发中实际上用的还是比较少。
局部内部类
局部内部类是定义在方法中、代码块中、构造器等执行体中
public class Test {
public static void main(String[] args) {
}
public static void go(){
class A{
}
abstract class B{
}
interface C{
}
}
}
匿名内部类
这是一种特殊的局部内部类
所谓匿名:指的是程序员不需要为这个类声明名字
new 类或接口(参数值…) {
方法实现(){}
};
new Animal(){
@Override
public void cry() {
}
};
public interface Swimming{
void swim();
}
public class Test {
public static void main(String[] args) {
go(new Swimming() {
@Override
public void swim() {
System.out.println(“猫也还行~~~");
}
});
}
public static void go(Swimming s){
System.out.println("开始============");
s.swim();
}
}
总结
- 匿名内部类的作用?
- 方便创建子类对象,最终目的为了简化代码编写。
- 匿名内部类的格式?
Animal a = new Employee() { public void run() { }};a. run();
- 匿名内部类的特点?
- 匿名内部类是一个没有名字的内部类,同时也代表一个对象。
- 匿名内部类的对象类型,相当于是当前new的那个类型的子类类型。
泛型
认识泛型
定义类、接口、方法时,同时声明的类型变量(如:<E>) ,称为泛型。
集合体系的全部接口和实现类都是支持泛型的使用的。
泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
集合体系的全部接口和实现类都是支持泛型的使用的。
public class ArrayList<E>{ . . . }
**作用: **
- 作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
- 本质:把具体的数据类型作为参数传给类型变量
- 分类:泛型类、泛型接口、泛型方法
泛型的好处:
- 统一数据类型。
- 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来。
修饰符 class 类名<类型变量,类型变量,…> {
}
public class ArrayList<E>{ . . . }
注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
1、泛型类的核心思想:
- 把出现泛型变量的地方全部替换成传输的真实数据类型
2、泛型类的作用
- 编译阶段约定操作的数据的类型,类似于集合的作用。
- 方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性
泛型接口
修饰符 interface 接口名<类型变量,类型变量,…> { }
public interface A<E>{ . . . }
注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V 等
作用: 泛型接口可以让实现类选择当前需要操作的数据类型
原理: 实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。
作用: 泛型接口可以约束实现类,实现类可以在实现接口的时候传入自己操作的数据类型这样重写的方法都将是针对于该类型的操作。
泛型方法
修饰符 <类型变量,类型变量,…> 返回值类型 方法名(形参列表) { }
public static <T> void test(T t){ } 对
public E get(int index){ 错
return (E) arr[index];
}
泛型通配符、上下限
- 通配符
- 就是 “?” ,可以在“使用泛型”的时候代表一切类型; E T K V 是在定义泛型的时候使用。
- 泛型的 上 下限
- 泛型上限: ? extends Car: ? 能接收的必须是Car或者其子类 。
- 泛型下限:? super Car :? 能接收的必须是Car或者其父类。
泛型的擦除问题和注意事项
- 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
- 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
常用API
什么是API?
- API(Application Programming interface) 应用程序编程接口。
- 简单来说:就是Java帮我们已经写好的一些方法,我们直接拿过来用就可以了。
Object类的作用:
- 一个类要么默认继承了Object类,要么间接继承了Object类,Object类是Java中的祖宗类。
- Object作为所有类的父类,提供了很多常用的方法给每个子类对象拿来使用。
方法名 | 说明 |
---|---|
public String toString() | 默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址 |
public boolean equals(Object o) | 默认是比较当前对象与另一个对象的地址是否相同,相同返回true,不同返回false |
Object的toString方法:
问题引出
l开发中直接输出对象,默认输出对象的地址其实是毫无意义的。
l开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息。
toString存在的意义
- 父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息!!
- Object的toString方法的基本作用是什么,存在的意义是什么?
- 基本作用:给子类继承,子类对象调用可以返回自己的地址。
- 意义:让子类重写,以便返回子类对象的内容。
Object的equals方法:
-
Object的equals方法的基本作用,存在的意义是什么?
-
基本作用:默认是与另一个对象比较地址是否一样
-
存在的意义:让子类重写,以便比较对象的内容是否相同。
-
Objects的常见方法:
方法名 | 说明 |
---|---|
public static boolean equals(Object a, Object b) | 比较两个对象的,底层会先进行非空判断,从而可以避免空指针异常。再进行equals比较 |
public static boolean isNull(Object obj) | 判断变量是否为null ,为null返回true ,反之 |
- 对象进行内容比较的时候建议使用什么?为什么?
- 建议使用Objects提供的equals方法。
- 比较的结果是一样的,但是更安全。
Object类提供的对象克隆方法
当某个对象调用这个方法时,这个方法会复制一个一模一样的新对象返回。
方法名 | 说明 |
---|---|
protected Object clone() | 对象克隆 |
浅克隆
拷贝出的新对象,与原对象中的数据一模一样(引用类型拷贝的只是地址)
深克隆
- 对象中基本类型的数据直接拷贝。
- 对象中的字符串数据拷贝的还是地址。
- 对象中还包含的其他对象,不会拷贝地址,会创建新对象。
包装类
为什么要有包装类?
基本类型的数据 | byte | short | int | long | char | float | double | boolean |
---|
包装类就是把基本类型的数据包装成对象。
基本数据类型 | 对应的包装类(引用数据类型) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
基本类型的数据包装成对象的方案 |
---|
public Integer(int value):已过时 |
public static Integer valueOf(int i) |
自动装箱: | 自动拆箱: |
---|---|
基本数据类型可以自动转换为包装类型。 | 包装类型可以自动转换为基本数据类型。 |
包装类其他常见操作
可以把基本类型的数据转换成字符串类型。
public static String toString(double d) |
---|
public String toString() |
可以把字符串类型的数值转换成数值本身对应的数据类型。
public static int parseInt(String s) |
---|
public static Integer valueOf(String s) |
StringBuilder
StringBuilder概述
- StringBuilder是一个可变的字符串的操作类,我们可以把它看成是一个对象容器。
- 使用StringBuilder的核心作用:操作字符串的性能比String要更高(如拼接、修改等)。
StringBuilder构造器
名称 | 说明 |
---|---|
public StringBuilder() | 创建一个空白的可变的字符串对象,不包含任何内容 |
public StringBuilder(String str) | 创建一个指定字符串内容的可变字符串对象 |
StringBuilder常用方法
方法名称 | 说明 |
---|---|
public StringBuilder append(任意类型) | 添加数据并返回StringBuilder对象本身 |
public StringBuilder reverse() | 将对象的内容反转 |
public int length() | 返回对象内容长度 |
public String toString() | 通过toString()就可以实现把StringBuilder转换为String |
- 为什么拼接、反转字符串建议使用StringBuilder?
- StringBuilder:内容是可变的、拼接字符串性能好、代码优雅。
- String :内容是不可变的、拼接字符串性能差。
- 定义字符串使用String
- 拼接、修改等操作字符串使用StringBuilder
总结
- 1、String和StringBuilder的区别是什么,分别适合什么场景?
- String: 是不可变字符串、频繁操作字符串会产生很多无用对象,性能差。
适合字符串内容不变的场景 - StringBuilder:是内容可变的字符串、拼接字符串性能好、代码优雅。
适合字符串内容频繁变化的场景
- String: 是不可变字符串、频繁操作字符串会产生很多无用对象,性能差。
- 2、StringBuilder和StringBuffer的区别是什么,分别适合什么场景?
- StringBuilder和StringBuffer都是可变字符串
- StringBuffer 线程安全, 性能稍差
- StringBuilder 线程不安全, 性能更高
StringJoiner
既能高效,又能实现更方便的拼接?
速度慢
public class Test {
public static void main(String[] args) {
String s = "";
for (int i = 0; i < 1000000; i++) {
s += "abc";
}
System.out.println(s);
}
}
速度快
public static String getArrayData(int[] arr){
// 1、判断arr是否为null
if(arr == null){
return null;
}
// 2、arr数组对象存在。 arr = [11, 22, 33]
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length - 1){
sb.append(arr[i]);
}else {
sb.append(arr[i]).append(", ");
}
}
sb.append("]");
return sb.toString();
}
JDK8开始才有的,跟StringBuilder一样,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的。
**好处:**不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁
构造器 | 说明 |
---|---|
public StringJoiner (间隔符号) | 创建一个StringJoiner对象,指定拼接时的间隔符号 |
public StringJoiner (间隔符号,开始符号,结束符号) | 创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号 |
方法名称 | 说明 |
---|---|
public StringJoiner add (添加的内容) | 添加数据,并返回对象本身 |
public int length() | 返回长度 ( 字符出现的个数) |
public String toString() | 返回一个字符串(该字符串就是拼接之后的结果) |