内部类与包装类
1、内部类
1)内部类概述
内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。
public class People{
// 内部类
public class Heart{
}
}
内部类的使用场景、作用:
1、当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构可以选择使用内部类来设计。
2、内部类通常可以方便访问外部类的成员,包括私有的成员。
3、内部类提供了更好的封装性,内部类本身就可以用private protectecd等修饰,封装性可以做更多控制。
2)静态内部类
//有static修饰,属于外部类本身
//与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已
public class Outer{
//静态成员内部类
public static class Inner{
}
}
//创建格式
//外部类名.内部类名 对象名 = new 外部类名.内部类构造
Outer.Inner in = new Outer.Inner();

不能访问外部类的实例成员,因为静态先于对象存在
3)成员内部类
//无static修饰,属于外部类的对象
//JDK16之前,成员内部类中不能定义静态成员,JDK 16开始也可以定义静态成员了。
public class Outer{
public class Inner{
}
}
//创建格式
//外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器
Outer.Inner in = new Outer().new Inner();
//静态成员用 外部类名.内部类名.名字 访问
Outer.Inner.test();

//面试题
//请观察如下代码,写出合适的代码对应其注释要求输出的结果。
class People{
private int heartbeat = 150;
public class Heart{
private int heartbeat = 110;
public void show(){
int heartbeat = 78;
System.out.println(heartbeat);//78
System.out.println(this.heartbeat); // 110
System.out.println(People.this.heartbeat); // 150
}
}
}
4)局部内部类(鸡肋,没啥用)
无默认的内部类
局部内部类放在方法、代码块、构造器等执行体中。有效空间只是当前区域。
局部内部类的类文件名为: 外部类$N内部类.class
5)匿名内部类
局部内部类有的限制,匿名内部类也都存在
匿名内部类:本质上是一个没有名字的局部内部类,定义在方法中、代码块中等。
作用:方便创建子类对象,最终目的为了简化代码编写。

使用匿名内部类都前提是实现某个接口或继承某个类
public class Out {
public static void main(String[] args) {
//使用匿名内部类代替
// AIn ain = new Aimp();
// ain.a();
// AIn ain1 = new AIn() { // xxx implements AIn
// public void a() {
// System.out.println("使用匿名内部类实现a");
// };
// };
//
//匿名内部类
AIn ai = new AIn() { // xxx implements AIn
@Override
public void a() {
System.out.println("匿名内部类实现接口中的方法");
}
};
ai.a();
BClass b = new BClass() { // xxx extends BClass
@Override
public void b() {
System.out.println("使用的是匿名内部类实现BClass中的抽象方法");
}
};
b.b();
}
}
abstract class BClass{
public abstract void b();
}
interface AIn{
public void a();
}
//class Aimp implements AIn{
//
// @Override
// public void a() {
// System.out.println("实现a");
// }
//}


6)设计模式:适配器Adapter模式
interface AIn{
public void a();
public void b();
public void c();
public void d();
}
/**
* 创建一个适配器类对接口的所有方法做空实现,不然匿名类需要对接口所有的抽象方法实现
* @author Administrator
*
*/
class AInAdapter implements AIn{
@Override
public void a() {
}
@Override
public void b() {
}
@Override
public void c() {
}
@Override
public void d() {
}
}
AIn ad = new AInAdapter() { // xxxx extends AInAdapter
//这里就只需要让匿名内部类继承适配器就可以选择要用的方法进行重写就可以了
@Override
public void a() {
System.out.println("匿名内部类重写适配器类中的某一个需要的方法");
}
};
ad.a();
7)Lambda表达式
JDK1.8新特性
作用:简化匿名内部类的使用,提出函数接口式编程
使用时要求:接口中只有一个方法才能使用
public abstract interface ILambda {
public abstract void test();
}
public class Demo02 {
public static void main(String[] args) {
// ILambda lambda = new ILambda() {
//
// @Override
// public void test() {
// System.out.println("匿名内部类");
// }
// };
// lambda.test();
//使用Lambda表达式 ----无参数
//需要传参数i时需要放在()中(i为形参),若只有一个参数可以省去()
//有返回值在代码中加入return
//只有一行代码是甚至可以省去外面的{};
ILambda lambda1 =() -> {
System.out.println("使用Lambda");
};
lambda1.test();
}
}
2、语法
1)package
作用:管理类
注:1)在同一个包中,不允许有相同的类出现。在不同的包中,允许有相同的类出现。
2)创建包 new --->pakage
命名规则:公司名称.项目名称.功能名称
.(点)表示的是层级,对应磁盘上的文件夹
3)同一个包中的东西可以直接拿来使用。但要想使用其他包中的类,需要导包
// import 包名.类名
//import 包名.*; //导入包中的所有类
package test;
import day01.Chair;
public class Demo01 {
public static void main(String[] args) {
Person p = new Person();
Chair c = new Chair();
}
}
4)当在一个地方要用两个不同包中的相同类时,只能导入一个包,另一个直接在类前面加上包名
调用不同包中的类时,其他包中的类要用get/set方法来获取值
test.Person person = new test.Person();//test
day01.Person person1 = new day01.Person();//day01
5)java.lang. 所有类都不需要导包
2)权限修饰符
public:公有,对所有用户开放,所有用户可以直接调用。包内包外的任何类(包括子类和普通类)都可以访问。
可以修饰数据成员、构造方法、方法成员、类(在class文件中只能有一个public类,且与源文件名字相同)。
private:私有,除了class自己外,任何人都不可以直接使用,即便是子女。
可以修饰数据成员、构造方法、方法成员,不能修饰类(指外部类,不考虑内部类)
protected:保护,对子女来说是public可以自由使用,但是对于其他不同包中的类,就变成了private,同一个包中可以访问。
可以修饰数据成员、构造方法、方法成员、不能修饰类(指外部类,不考虑内部类)
default:默认权限。包内的任何类都可以访问、包外的任何内都不能访问(包括继承了此类的子类)
可以修饰数据成员、构造方法、方法成员、不能修饰类(指外部类,不考虑内部类)

3)final
final修饰类,类不能被继承
final修饰方法,方法不能被重写
final修饰变量,变量有且仅能被赋值一次
final修饰变量
变量:1、局部变量2、成员变量(实例成员变量、静态成员变量)


注意:
final修饰的变量是基本数据类型----存储的数据值不能变
final修饰的变量是引用数据类型----存储的地址值不能变,但地址指向的内容会变
4)常量
常量的概述和基本作业:

常量做信息标志和分类

4)枚举
枚举是Java中的一种特殊类型,类的对象是有限个、确定的
作用:是为了做信息的标志和信息的分类

javac与javap命令实现编译与反编译后,代码为:

枚举的使用场景:做信息的标志和信息的分类

代码:

在main中调用时只有UP DOWN LEFT RIGHT四种选项

定义一个枚举类
/**
* 定义一个枚举类型
* @author Administrator
*
*/
public enum WeekDay {
MonDay,//星期一
TuesDay,//星期二
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
使用枚举作为参数
public static void main(String[] args) {
panDuanWeek(WeekDay.Sunday);
}
/**
* 使用枚举类型作为参数
* @param weekDay
*/
public static void panDuanWeek(WeekDay weekDay) {
switch (weekDay) {
case MonDay:
System.out.println("星期一");
break;
case TuesDay:
System.out.println("星期二");
break;
case Wednesday:
System.out.println("星期三");
break;
case Thursday:
System.out.println("星期四");
break;
case Friday:
System.out.println("星期五");
break;
case Saturday:
System.out.println("星期六");
break;
case Sunday:
System.out.println("星期日");
}
}
注意:在打印等情况下会调用toString方法
3、包装类
Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能,如果想要我们的基本类型像对象一样操作,就可以使用基本类型对应的包装类,如下:
集合与泛型只支持包装类
包装类可以是null
| 基本类型 | 对应的包装类(位于java.lang包中) |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
1)装箱与拆箱
基本类型与对应的包装类对象之间,来回转换的过程称为”装箱“与”拆箱“:
- 装箱:从基本类型转换为对应的包装类对象。
- 拆箱:从包装类对象转换为对应的基本类型。
用Integer与 int为例:(看懂代码即可)
基本数值---->包装对象
Integer i = new Integer(4);//使用构造函数函数
Integer iii = Integer.valueOf(4);//使用包装类中的valueOf方法
包装对象---->基本数值
int num = i.intValue();
2)自动装箱与自动拆箱
由于我们经常要做基本类型与包装类之间的转换,从Java 5(JDK 1.5)开始,基本类型与包装类的装箱、拆箱动作可以自动完成。例如:
Integer i = 4;//自动装箱。相当于Integer i = Integer.valueOf(4);
i = i + 5;//等号右边:将i对象转成基本数值(自动拆箱) i.intValue() + 5;
//加法运算完成后,再次装箱,把基本数值转成对象。
3)内存原理等

public class Demo05 {
public static void main(String[] args) {
int num = 10;
Integer n=Integer.valueOf(num);//实现装箱过程 自动装箱
//值在-128到127之间 这里返回的是一个数组下标 eg:-128---x001
//Integer n = Integer.valueOf(10);
//打印是又调用了toString方法,返回数值的字符串,而不是地址
System.out.println(Integer.valueOf(num));
//值大于127了,执行下面的代码return,又新建对象,不再到数组中取值
//所以是两个不同对象的空间,地址就不相同了
//value是int型常量
// return new Integer(i);
// public Integer(int value) {
// this.value = value;
// }
//value =128
Integer n2 = Integer.valueOf(128);
Integer i1 = 10;
Integer i2 = 10;
System.out.println(i1==i2);
i1 = 128;
i2 = 128;
System.out.println(i1==i2);
//被装箱后的引用数据类型
Integer i3 = 5;//隐藏了这个Integer.valueOf(5);
//Integer i3 = new Integer(5);与这句效果类似
//拆箱
//value = 5;
// public int intValue() {
// return value;
// }
int i4 = i3;//隐藏了i3.intValue(); return了int类型的value
//Long Short类似
//Byte
//装箱过程
byte b1 = 10;
Byte b2 =b1;//Byte b2 = Byte.valueOf((byte) 10);
Byte b4 = b1;
System.out.println(b2==b4);//都去数组中找,不创建新的对象,返回true
//拆箱
byte b3 = b2;//byte b3 = b2.byteValue();
//Float Double都没有数组的存在,直接new 一个新对象
float f1 = 5.0f;
Float f2 = f1;//Float.valueOf(5.0f);
Float f3 = f1;
System.out.println(f2==f3);//因为都是new新对象,所以是false
//Character ASCII码刚好128个,有一个已经设定好的静态数组
char ch1 = 'a';
Character ch2 = ch1;//Character ch2 = Character.valueOf(ch1);
Character ch3 = ch1;
System.out.println(ch2==ch3);//true
//Boolean
boolean bo1 = false;
//Boolean 底层是static 静态对象,只会被初始化一次
//public static final Boolean FALSE = new Boolean(false);
//public static final Boolean TRUE = new Boolean(true);
Boolean bo2 = bo1;//Boolean.valueOf(bo1);
Boolean bo3 = false;
System.out.println(bo2==bo3);
}
}
面试题:
//基本数据类型值比较值
int num1 = 10;
int num2 = 10;
Integer num3 = new Integer(10);
Integer num4 = new Integer(10);
Integer num5 = 10;
Integer num6 = 10;
Integer num7 = 160;
Integer num8 = 160;
System.out.println(num1 == num2);//true
System.out.println(num3 == num2);//true 只要有一方是基本数据类型就是比较值
System.out.println(num3 == num4);//false 两个不同的对象地址不同
System.out.println(num5 == num4);//false 4是new的对象的地址,5是在Integer cache[]中找打该数位置的地址
System.out.println(num5 == num6);//true 都是在Integer cache[]中找打该数位置的地址,值一样地址也一样
System.out.println(num7 == num8);//false 超出Integer cache[]范围,重新new了两个Integer对象,地址不同
4)包装类特有功能



浙公网安备 33010602011771号