<1>包装类
将数据类型包装为一个类
1.1 装箱和拆箱
概念
装箱:
把基本数据类型转为包装类对象。
转为包装类的对象,是为了使用专门为对象设计的API和特性
拆箱:
把包装类对象拆为基本数据类型。
转为基本数据类型,一般是因为需要运算,Java中的大多数运算符是为基本数据类型设计的。比较、算术等
语法格式
Integer integer1 = new Integer(100);
包装类 名字 = new 包装类
比较一下类的语法,你可以发现不能说大同小异只能说一模一样
1.2 integer类
例如
public class Test03 {
public static void main(String[] args) {
int num = 40;
String str = Integer.toString(num); // 将数字转换成字符串
String str1 = Integer.toBinaryString(num); // 将数字转换成二进制
String str2 = Integer.toHexString(num); // 将数字转换成八进制
String str3 = Integer.toOctalString(num); // 将数字转换成十六进制
System.out.println(str + "的二进制数是:" + str1);
System.out.println(str + "的八进制数是:" + str3);
System.out.println(str + "的十进制数是:" + str);
System.out.println(str + "的十六进制数是:" + str2);
}
}
1.3 character类
1.4 Boolean类
1.4 特点
包装类缓存对象:
记忆方法:缓存对象-128~127,character没有负的所以是0~127。
大家千万不要以为这个是没有用的,我在牛客网刷题的时候就碰到了这样的题,
答案:AB
类型转换问题:
并不是所有时候自动装箱或开箱,这里比较复杂,就把查到的一篇文章附在这里吧。
什么时候不会自动拆箱装箱https://blog.csdn.net/qq_51272114/article/details/125370092
包装类对象不可变:
通过形参修改对象的属性值,会影响实参的属性值。这类Integer等包装类对象是“不可变”对象,即一旦修改,就是新对象,和实参就无关了
public class TestExam {
public static void main(String[] args) {
int i = 1;
Integer j = new Integer(2);
Circle c = new Circle();
change(i,j,c);
System.out.println("i = " + i);//1
System.out.println("j = " + j);//2
System.out.println("c.radius = " + c.radius);//10.0
}
/*
* 方法的参数传递机制:
* (1)基本数据类型:形参的修改完全不影响实参
* (2)引用数据类型:通过形参修改对象的属性值,会影响实参的属性值
* 这类Integer等包装类对象是“不可变”对象,即一旦修改,就是新对象,和实参就无关了
*/
public static void change(int a ,Integer b,Circle c ){
a += 10;
// b += 10;//等价于 b = new Integer(b+10);
c.radius += 10;
/*c = new Circle();
c.radius+=10;*/
}
}
class Circle{
double radius;
}
<2>内部类
2.1成员内部类
静态内部类
有static修饰的成员内部类叫做静态内部类
-
和其他类一样,它只是定义在外部类中的另一个完整的类结构
-
可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
-
可以在静态内部类中声明属性、方法、构造器等结构,包括静态成员
-
可以使用abstract修饰,因此它也可以被其他类继承
-
可以使用final修饰,表示不能被继承
-
编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。
-
-
和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private
-
外部类只允许public或缺省的
-
-
只可以在静态内部类中使用外部类的静态成员
-
在静态内部类中不能使用外部类的非静态成员哦
-
如果在内部类中有变量与外部类的静态成员变量同名,可以使用“外部类名."进行区别
-
-
在外部类的外面不需要通过外部类的对象就可以创建静态内部类的对象(通常应该避免这样使用)
非静态内部类(实例内部类)
没有static修饰的成员内部类叫做非静态内部类 ,有的也叫实例内部类。
-
和其他类一样,它只是定义在外部类中的另一个完整的类结构
-
可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
-
可以在非静态内部类中声明属性、方法、构造器等结构,但是不允许声明静态成员,但是可以继承父类的静态成员,而且可以声明静态常量。
-
可以使用abstract修饰,因此它也可以被其他类继承
-
可以使用final修饰,表示不能被继承
-
编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名和$符号。
-
-
和外部类不同的是,它可以允许四种权限修饰符:public,protected,缺省,private
-
外部类只允许public或缺省的
-
-
还可以在非静态内部类中使用外部类的所有成员,哪怕是私有的
-
在外部类的静态成员中不可以使用非静态内部类哦
-
就如同静态方法中不能访问本类的非静态成员变量和非静态方法一样
-
-
在外部类的外面必须通过外部类的对象才能创建非静态内部类的对象(通常应该避免这样使用)
-
如果要在外部类的外面使用非静态内部类的对象,通常在外部类中提供一个方法来返回这个非静态内部类的对象比较合适
-
因此在非静态内部类的方法中有两个this对象,一个是外部类的this对象,一个是内部类的this对象
-
public class TestMemberInnerClass {
public static void main(String[] args) {
Outer.outMethod();
System.out.println("-----------------------");
Outer out = new Outer();
out.outFun();
System.out.println("####################################");
Outer.Inner.inMethod();
System.out.println("------------------------");
Outer.Inner inner = new Outer.Inner();
inner.inFun();
System.out.println("####################################");
Outer outer = new Outer();
// Outer.Nei nei = outer.new Nei();
Outer.Nei nei = out.getNei();
nei.inFun();
}
}
class Outer{
private static String a = "外部类的静态a";
private static String b = "外部类的静态b";
private String c = "外部类对象的非静态c";
private String d = "外部类对象的非静态d";
static class Inner{
private static String a ="静态内部类的静态a";
private String c = "静态内部类对象的非静态c";
public static void inMethod(){
System.out.println("Inner.inMethod");
System.out.println("Outer.a = " + Outer.a);
System.out.println("Inner.a = " + a);
System.out.println("b = " + b);
// System.out.println("c = " + c);//不能访问外部类和自己的非静态成员
// System.out.println("d = " + d);//不能访问外部类的非静态成员
}
public void inFun(){
System.out.println("Inner.inFun");
System.out.println("Outer.a = " + Outer.a);
System.out.println("Inner.a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
// System.out.println("d = " + d);//不能访问外部类的非静态成员
}
}
class Nei{
private String a = "非静态内部类对象的非静态a";
private String c = "非静态内部类对象的非静态c";
public void inFun(){
System.out.println("Nei.inFun");
System.out.println("Outer.a = " + Outer.a);
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("Outer.c = " + Outer.this.c);
System.out.println("c = " + c);
System.out.println("d = " + d);
}
}
public static void outMethod(){
System.out.println("Outer.outMethod");
System.out.println("a = " + a);
System.out.println("Inner.a = " + Inner.a);
System.out.println("b = " + b);
// System.out.println("c = " + c);
// System.out.println("d = " + d);
Inner in = new Inner();
System.out.println("in.c = " + in.c);
}
public void outFun(){
System.out.println("Outer.outFun");
System.out.println("a = " + a);
System.out.println("Inner.a = " + Inner.a);
System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("d = " + d);
Inner in = new Inner();
System.out.println("in.c = " + in.c);
}
public Nei getNei(){
return new Nei();
}
}
2.2局部内部类
局部内部类
语法格式:
【修饰符】 class 外部类{
【修饰符】 返回值类型 方法名(【形参列表】){
【final/abstract】 class 内部类{
}
}
}
局部内部类的特点:
-
和外部类一样,它只是定义在外部类的某个方法中的另一个完整的类结构
-
可以继承自己的想要继承的父类,实现自己想要实现的父接口们,和外部类的父类和父接口无关
-
可以在局部内部类中声明属性、方法、构造器等结构,但不包括静态成员,除非是从父类继承的或静态常量
-
可以使用abstract修饰,因此它也可以被同一个方法的在它后面的其他内部类继承
-
可以使用final修饰,表示不能被继承
-
编译后有自己的独立的字节码文件,只不过在内部类名前面冠以外部类名、$符号、编号。
-
这里有编号是因为同一个外部类中,不同的方法中存在相同名称的局部内部类
-
-
-
和成员内部类不同的是,它前面不能有权限修饰符等
-
局部内部类如同局部变量一样,有作用域
-
局部内部类中是否能访问外部类的静态还是非静态的成员,取决于所在的方法
-
局部内部类中还可以使用所在方法的局部常量,即用final声明的局部变量
-
JDK1.8之后,如果某个局部变量在局部内部类中被使用了,自动加final
-
为什么在局部内部类中使用外部类方法的局部变量要加final呢?考虑生命周期问题。
-
public class TestLocalInner {
public static void main(String[] args) {
Runner runner = Outer.getRunner();
runner.run();
System.out.println("-------------------");
Outer.outMethod();
System.out.println("-------------------");
Outer out = new Outer();
out.outTest();
}
}
class Outer{
private static String a = "外部类的静态a";
private String b = "外部类对象的非静态b";
public static void outMethod(){
System.out.println("Outer.outMethod");
final String c = "局部变量c";
class Inner{
public void inMethod(){
System.out.println("Inner.inMethod");
System.out.println("out.a = " + a);
// System.out.println("out.b = " + b);//错误的,因为outMethod是静态的
System.out.println("out.local.c = " + c);
}
}
Inner in = new Inner();
in.inMethod();
}
public void outTest(){
class Inner{
public void inMethod(){
System.out.println("out.a = " + a);
System.out.println("out.b = " + b);//可以,因为outTest是非静态的
}
}
Inner in = new Inner();
in.inMethod();
}
public static Runner getRunner(){
class LocalRunner implements Runner{
@Override
public void run() {
System.out.println("LocalRunner.run");
}
}
return new LocalRunner();
}
}
interface Runner{
void run();
}
匿名内部类
当我们在开发过程中,需要用到一个抽象类的子类的对象或一个接口的实现类的对象,而且只创建一个对象,而且逻辑代码也不复杂。那么我们原先怎么做的呢?
(1)编写类,继承这个父类或实现这个接口
(2)重写父类或父接口的方法
(3)创建这个子类或实现类的对象
这里,因为考虑到这个子类或实现类是一次性的,那么我们“费尽心机”的给它取名字,就显得多余。那么我们完全可以使用匿名内部类的方式来实现,避免给类命名的问题。
new 父类(【实参列表】){
重写方法...
}
//()中是否需要【实参列表】,看你想要让这个匿名内部类调用父类的哪个构造器,如果调用父类的无参构造,那么()中就不用写参数,如果调用父类的有参构造,那么()中需要传入实参
new 父接口(){
重写方法...
}
//()中没有参数,因为此时匿名内部类的父类是Object类,它只有一个无参构造
注意:
匿名内部类是一种特殊的局部内部类,只不过没有名称而已。所有局部内部类的限制都适用于匿名内部类。例如:
-
在匿名内部类中是否可以使用外部类的非静态成员变量,看所在方法是否静态
-
在匿名内部类中如果需要访问当前方法的局部变量,该局部变量需要加final
思考:这个对象能做什么呢?
(1)使用匿名内部类的对象直接调用方法
interface A{
void a();
}
public class Test{
public static void main(String[] args){
new A(){
@Override
public void a() {
System.out.println("aaaa");
}
}.a();
}
}
(2)通过父类或父接口的变量多态引用匿名内部类的对象
interface A{
void a();
}
public class Test{
public static void main(String[] args){
A obj = new A(){
@Override
public void a() {
System.out.println("aaaa");
}
};
obj.a();
}
}
(3)匿名内部类的对象作为实参
interface A{
void method();
}
public class Test{
public static void test(A a){
a.method();
}
public static void main(String[] args){
test(new A(){
@Override
public void method() {
System.out.println("aaaa");
}
});
}
}
<3>接口
3.1语法格式
格式
【修饰符】 interface 接口名{
//接口的成员列表:
// 公共的静态常量
// 公共的抽象方法
// 公共的默认方法(JDK1.8以上)
// 公共的静态方法(JDK1.8以上)
// 私有方法(JDK1.9以上)
}
接口成员说明
接口定义的是多个类共同的公共行为规范,这些行为规范是与外部交流的通道,这就意味着接口里通常是定义一组公共方法。
在JDK8之前,接口中只允许出现:
(1)公共的静态的常量:其中public static final可以省略
(2)公共的抽象的方法:其中public abstract可以省略
理解:接口是从多个相似类中抽象出来的规范,不需要提供具体实现
在JDK1.8时,接口中允许声明默认方法和静态方法:
(3)公共的默认的方法:其中public 可以省略,建议保留,但是default不能省略
(4)公共的静态的方法:其中public 可以省略,建议保留,但是static不能省略
在JDK1.9时,接口又增加了:
(5)私有方法
除此之外,接口中不能有其他成员,没有构造器,没有初始化块,因为接口中没有成员变量需要动态初始化。
3.2接口使用
注意事项:
接口的特征:
1.接口中方法的声明不需要其他修饰符,在接口中声明的方法,将隐式地声明为公有的(public)和抽象的(abstract)。
2.在 Java 接口中声明的变量其实都是常量,接口中的变量声明,将隐式地声明为 public、static 和 final,即常量,所以接口中定义的变量必须初始化。
3.接口没有构造方法,不能被实例化
接口的实现:
1.一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。
2.一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽象方法);否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类。
使用接口的静态成员:
接口不能直接创建对象,但是可以通过接口名直接调用接口的静态方法和静态常量
接口名 . 调用的方法名
类实现接口(implements)
接口不能创建对象,但是可以被类实现(implements
,类似于被继承)。
3.3接口冲突:
父类优先原则
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。代码如下:
方法名冲突
当一个类同时实现了多个父接口,而多个父接口中包含方法签名相同的默认方法时 ,选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法。
public class Girl implements Friend,BoyFriend{
@Override
public void date() {
//(1)保留其中一个父接口的
// Friend.super.date();
// BoyFriend.super.date();
//(2)完全重写
System.out.println("学Java");
}
}
当一个子接口同时继承了多个接口,而多个父接口中包含方法签名相同的默认方法时 ,在实现类覆盖重写。
常量冲突
1.当子类继承父类又实现父接口,而父类中存在与父接口常量同名的成员变量,并且该成员变量名在子类中仍然可见。
2.当子类同时继承多个父接口,而多个父接口存在相同同名常量。
解决方法:接口名.变量名
public class SuperClass {//接口1
int x = 1;
}
public interface SuperInterface {//接口2
int x = 2;
int y = 2;
}
public interface MotherInterface {//接口3
int x = 3;
}
public class SubClass extends SuperClass implements SuperInterface,MotherInterface {
public void method(){
// System.out.println("x = " + x);//模糊不清
System.out.println("super.x = " + super.x);
System.out.println("SuperInterface.x = " + SuperInterface.x);
System.out.println("MotherInterface.x = " + MotherInterface.x);
System.out.println("y = " + y);//没有重名问题,可以直接访问
}
}
<4>枚举
4.1使用
【修饰符】 enum 枚举类名{
常量对象列表
}【修饰符】 enum 枚举类名{
常量对象列表;
其他成员列表;
}
public enum Week {
MONDAY("星期一"),
TUESDAY("星期二"),
WEDNESDAY("星期三"),
THURSDAY("星期四"),
FRIDAY("星期五"),
SATURDAY("星期六"),
SUNDAY("星期日");
private final String description;
private Week(String description){
this.description = description;
}
@Override
public String toString() {
return super.toString() +":"+ description;
}
}
4.2常用方法
1.String toString( ): 默认返回的是常量名(对象名),可以继续手动重写该方法!
2.String name( ):返回的是常量名(对象名)
3.int ordinal( ):返回常量的次序号,默认从0开始
4.枚举类型[ ] values( ):返回该枚举类的所有的常量对象,返回类型是当前枚举的数组类型,是一个静态方法
5.枚举类型 valueOf(String name):根据枚举常量对象名称获取枚举对象