一、经典接口
1、java.lang.Comparable接口:自然排序/比较接口,或者也称为默认排序
抽象方法:int compareTo(Object o)
返回值结果: .前面的this 大于 ()中的指定对象o, 返回正整数
返回值结果: .前面的this 小于 ()中的指定对象o, 返回负整数
返回值结果: .前面的this 等于 ()中的指定对象o, 返回0
2、java.util.Comparator接口:定制排序/比较接口,或者也称为挽救的比较器
抽象方法:int compare(Object o1, Object o2)
返回值结果: o1 大于 o2, 返回正整数
返回值结果: o1 小于 o2, 返回负整数
返回值结果: o1 等于 o2, 返回0
二、包装类
1.、包装类是什么?
byte–>Byte
short–>Short
int–>Integer
long–>Long
float–>Float
double–>Double
char–>Character
boolean–>Boolean
void–>Void
2、如何使用包装类
(1)普通使用
Integer obj = new Integer(xx);
(2)和基本数据类型转换
装箱:
基本数据类型 --> 包装类的对象
拆箱:
包装类对象 --> 基本数据类型
手动装箱:
①用包装类的构造器,用基本数据类型的值/变量创建一个包装类对象
②用包装类的valueOf方法,把基本数据类型的值/变量转变为一个包装类对象 since1.5从JDK1.5之后才有
自动装箱:JDK1.5之后
①当把基本数据类型的值/变量赋值给引用数据类型的变量时,自动会装箱
②每一种基本数据类型只与自己的包装类之间进行自动装箱
手动拆箱:
①包装类对象调用xxValue()
例如:Integer的对象,可以调用 .intValue()返回int值
自动拆箱:
①当把包装类的对象赋值给基本数据类型的变量时,会自动拆箱
②当包装类的对象遇到基本数据类型的运算符(>,<等)时,会自动拆箱
总结:数据类型的转换
(1)基本数据类型之间 :自动类型升级和强制类型转换
(2)引用数据类型之间:要求父子类,而且是编译时的转换,向上转型和向下转型
(3)基本数据类型与包装类之间:装箱与拆箱
(4)其他类型与字符串之间:
其他类型 -> 字符串:
①所有类型 + 字符串 结果就是字符串
②引用数据类型的对象.toString() 就是专为字符串
字符串 -> 其他类型
调用对应的parseXxx方法
public class TestWrapper {
public static void main(String[] args) {
Integer obj1 = new Integer(1);
Integer obj2 = new Integer(1);
System.out.println(obj1.equals(obj2));
System.out.println("----------------------------");
int a = 10;
// method(a);//JDK1.5之前 错误,a不是引用数据类型
//用构造器
// Integer obj = new Integer(a);
// method(obj);
//用valueOf方法
// Integer obj = Integer.valueOf(a);
// method(obj);
method(a);//class java.lang.Integer
System.out.println("----------------------------");
int num = 1;
// Double value = num; //num是int,它只会自动装箱为Integer的对象,而Integer的对象是不能赋值给Double
double d = num; //num自动类型升级为double
Double value = d;
System.out.println("----------------------------");
Integer obj3 = new Integer(30);
Integer obj4 = new Integer(30);
//手动拆箱
System.out.println(obj3.intValue() > obj4.intValue());
//自动拆箱
System.out.println(obj3 > obj4);
/*String str1 = "10";
String str2 = "10";
System.out.println(str1 > str2);*///不是包装类,就不会自动拆箱
}
public static void method(Object obj){
//....
//获取obj的运行时类型
System.out.println(obj.getClass());
}
}
3.包装类的缓存问题
Byte:-128~127
Short:-128~127
Integer:-128~127
Long:-128~127
Character:0~127 最早的ASCII表的范围。
Float和Double不缓存。
Boolean:true和false
4.包装类的方法
例如:Integer
(1)把字符串转为基本数据类型或它的包装类对象(几乎所有包装类都有对应)(重要)
①构造器
Integer obj = new Integer(字符串);
②valueOf方法
Integer obj = Integer.valueOf(字符串);
③parseInt方法
int value = Integer.parseInt(字符串)
(2)其他方法(不一定有通用性)(了解)
(3)比较两个基本数据类型的值(重要)
特别是double和float类型
例如:Double.compare(x,y)返回正、负、0整数
(4)转字母大小写 (Character) 重要
//方式一:
System.out.println((char)(letter-32));
//方式二:
System.out.println(Character.toUpperCase(letter));
(5) 获取每一种数据类型的最大值和最小值(了解 )
三、枚举
Java的数据类型:
1、基本数据类型
2、引用数据类型:
数组、类、接口、枚举、注解
1、什么是枚举类型?
其实本质上枚举也是一种类。
特殊:
(1)这种类型的对象是在整个程序中只有固定的有限的几个常量对象。
例如:星期、月份、季节、员工状态、订单状态等
(2)JDK1.5之后声明它的关键字从class变为enum
语法格式:
【修饰符】 enum 枚举类名{
常量对象列表 【;
其他成员;
】
}
说明:
(1)常量对象列表中每一个常量之间使用,分割,如果常量对象列表后面没有其他代码了,就不用加;,
如果常量对象列表后面还有其他代码,那么在常量对象列表最后要加一个;
(2)常量对象必须在枚举类中首行
(3)用enum声明的枚举类型,构造器自动私有化,无论你是否加private
(4)用enum声明的枚举类型,不能再继承其他类了,因为它默认的直接父类是java.lang.Enum
①父类中有两个成员变量:name,value
name是常量对象名,value是常量对象的序号,从0开始
②Enum类中重写了Object类的toString,默认返回的是对象的name
③在API中看不到的两个方法
static 枚举类型 valueOf(String name)
static 枚举类型[] values()
④switch在JDK1.5之后支持了枚举类型
回忆:首行
(1)super()和super(…)必须在子类构造器的首行
(2)this()和this(…)必须在本类构造器的首行
(3)package必须在.java源文件的代码首行
(4)枚举常量对象必须在枚举类的首行
四、内部类
1、静态内部类语法格式
【修饰符】 class 外部类{
【其他修饰符】 static class 内部类{
}
}
2、静态内部类特点
(1)静态内部类的权限修饰符:4种
(2)静态内部类也是一个类
①有自己的字节码文件,名字是 外部类名$静态内部类名.class
②类中的所有成员它都可以声明
③可以是abstract,可以是final
④继承自己的父类,实现接口们
⑤可以创建对象,只要它不是抽象的
(3)如何使用它
在外部类中使用静态内部类:
使用静态的成员:直接静态内部类名.成员
使用非静态的成员:先创建静态内部类的对象,然后对象.成员
在外部类的外面静态内部类:
使用静态的成员:直接静态内部类名.成员
使用非静态的成员:先创建静态内部类的对象,然后对象.成员
只不过在外面使用静态内部类时,要加外部类名.静态内部类名
(4)在静态内部类中使用外部类的成员
虽然说可以直接使用外部类的私有成员,但是在静态内部类中不能直接使用外部类的非静态成员。
(5)在外部类中使用静态内部类的成员
在外部类中也可以使用静态内部类的私有成员
public class TestStatic {
public static void main(String[] args) {
Outer.outMethod();
//直接在这里使用静态内部类
//(1)在这里调用Inner的inMethod()
Outer.Inner.inMethod();
//(2)在这里调用Inner的inTest()
Outer.Inner inner = new Outer.Inner();
inner.inTest();
}
}
class Outer{
private int a;
private static int b;
static class Inner{
private int c = 3;
private static int d = 4;
public static void inMethod(){
System.out.println("静态内部类的静态方法");
// System.out.println("外部类的a = " + a);
System.out.println("外部类的b = " + b);
}
public void inTest(){
System.out.println("静态内部类的非静态方法");
// System.out.println("外部类的a = " + a);
System.out.println("外部类的b = " + b);
}
}
public static void outMethod(){
//在这里使用Inner
//在这里调用Inner的inMethod()
// Inner.inMethod();
//在这里调用Inner的inTest()
Inner inner = new Inner();
inner.inTest();
//在这里使用Inner的private的c和d
System.out.println(inner.c);
System.out.println(Inner.d);
}
}
2.非静态内部类
1、语法格式
【修饰符】 class 外部类{
【修饰符】 class 内部类{
}
}
2、特点
(1)权限修饰符:4种
(2)非静态内部类也是一个类
①也有自己的字节码文件,外部类名$非静态内部类名.class
②非静态内部类中不能静态的成员(静态变量、静态方法、静态代码块、静态内部类)
但是,如果该静态成员是从父类继承的,可以
可以声明静态的常量
③可以是abstract,可以是final
④继承自己的父类,实现接口们
⑤可以创建对象,只要它不是抽象的
(3)在外部类中使用非静态内部类
在外部类的非静态方法中使用:先创建非静态内部类的对象,然后用对象.成员
在外部类的静态方法中使用:不能
(4)在外部类的外面使用非静态内部类
第一步:创建外部类的对象
第二步:获取内部类的对象
要么直接new,要么通过外部类的对象.方法获取内部类对象
第三步:通过内部类的对象.成员
总结:
拿到一个类型的对象的几种形式:
(1)直接new
变量 = new 类名(…);
(2)枚举类名.常量对象
变量 = 枚举类名.常量对象名;
(3)其他对象.方法(…) 该方法可以返回某个类型的对象
变量 = 其他对象.方法(…);
(5)外部类和非静态内部类可以互访私有成员
*/
public class TestNonStatic {
public static void main(String[] args) {
Outer outer = new Outer();
outer.outMethod();
//在这里调用Inner的inMethod()
// Outer.Inner inner = new Outer.Inner();//错误,因为Inner是作为Outer的非静态成员,所以需要Outer的对象
Outer out = new Outer();
Outer.Inner inner = out.new Inner();
inner.inMethod();
System.out.println("-------------------------------");
//在这里调用Inner的inMethod(),但是想要避免 out.new Inner() 这种写法
Outer out2 = new Outer();
Outer.Inner inner2 = out2.getInner();
inner2.inMethod();
}
}
class Outer{
private int a;
private static int b;
class Inner {
private int c;
public void inMethod(){
System.out.println("非静态内部类的非静态方法");
System.out.println("外部类的a =" + a);
System.out.println("外部类的b =" + b);
}
}
public void outMethod(){
//在这里调用Inner的inMethod()
Inner inner = new Inner();
inner.inMethod();
System.out.println("使用内部类的c = " + inner.c);
}
public static void outTest(){
//在这里调用Inner的inMethod()
// Inner inner = new Inner();//错误,因为outTest()方法是静态的,Inner是非静态
}
//调用这个方法,可以获取Inner的对象
public Inner getInner(){
return new Inner();
}
}
3.局部内部类(了解)
1、语法格式:
【修饰符】 class 外部类{
【修饰符】 返回值类型 方法名(【形参列表】){
【修饰符】 class 内部类{
}
}
}
2、特点
(1)权限修饰符:没有权限修饰符
(2)局部内部类也是一个类
①有自己的字节码文件,外部类名$编号局部内部类名.class
为什么有编号?因为同一个外部类中可能存在同名的多个局部内部类
②局部内部类中不能静态的成员(静态变量、静态方法、静态代码块、静态内部类)
但是,如果该静态成员是从父类继承的,可以
可以声明静态的常量
③可以是abstract,可以是final
④继承自己的父类,实现接口们
⑤可以创建对象,只要它不是抽象的
(3)在外部类中使用局部内部类
有作用域,仅限在作用域范围内使用
(4)在外部类的外面使用局部内部类
(5)那么能否在外部类的外面,获取到局部内部类的对象?
或者说,如果想要把局部内部类的对象,返回到外部类的外面使用,是否可以呢?
可以,通过方法的返回值返回内部类的对象,而且方法的返回值只能是它的父类或父接口类型。
(6)外部类和局部内部类可以互访私有的成员
但是:如果局部内部类是在静态方法中,不能使用外部类的非静态成员。
(7)局部内部类可以访问外部类的局部变量,但是是要注意作用域(特殊)
注意:该局部变量必须是final的。
JDK1.8之前必须手动加final,JDK1.8之后自动加final。
为什么呢?
如果把局部内部类的对象,返回到外部类的外面使用时,那么如果在局部内部类中使用了局部变量,
当返回局部内部类对象的方法运行结束之后,该局部变量的内存是会随着方法的出栈而消失,
那么就会出现访问不存在的内存问题。
此时其实编译帮局部内部类自动声明了一个隐形的成员变量,和刚刚的局部变量同名,初始化它的值。
所以避免认为是同一个值不统一问题,干脆规定值不能修改。