一、内部内
- 定义在 类 的 内部 的 类,内部类 与 外部类 有紧密的联系
- 内部类 离开了外部类 将失去意义
- 内部类 可以直接使用 外部类 的所有成员,【包括】私有成员
举个栗子
/** 内部内的基本语法
class Outer{ //外部类
class Inner{ //内部类
}
}
class Other{ //外部其他类
}
把【人*体】和【心脏】看作 类,【人*体】内有独特的 *NB*型血
【心脏】定义在了【人*体】,【人*体】与【心脏】有着紧密的联系
【人*体】离不开【心脏】,但【心脏】离开了【人*体】也将变得没有意义(不移植)
【心脏】可以使用【人*体】内独特的 *NB*型血
*/
class Test {
public static void main(String[] args) {
new 人体();
}
}
class 人体 {
//定义外部类成员变量
String BloodType = "NB";
public 人体() {
new 心脏();
}
class 心脏 {//定义内部内
//使用外部类成员变量BloodType
public 心脏(){
System.out.println("心脏正在使用 人体 的" + BloodType + "型血."); //输出: 心脏正在使用 人体 的NB型血.
}
}
}
- 一般来说 内部内都会用 private 修饰,会导致无法在新类使用该类的内部类;对此,我们可以在外部内中提供一个方法来帮我们调用内部内的方法。
class Test {
public static void main(String[] args) {
new Outer().getIner;
}
}
class Outer{
private class Inner {
public void showA(){System.out.println("Inner - showA");}
public void showB(){System.out.println("Inner - showA");}
public void showC(){System.out.println("Inner - showA");}
}
public void getIner(){
Inner i = new Inner();
i.showA();
}
}
但是这样会造成一个问题,当我们需要访问内部内的其他方法时,需要创建新的getIner(),当内部内中方法有很多时,我们需要的getIner()会非常庞大
对此我们可以进行一点小小的优化,让getIner()方法返回一个Inner对象给我们使用,而不是通过它来调用内部内的成员
class Test {
public static void main(String[] args) {
//Inner inner = new Outer().getIner; 这样会报错,因为Inner对象是private修饰的
Inter inner = new Outer().getIner();//接收到对象后就可以随意使用了
inner.showA();
inner.showB();
inner.showC();
}
}
interface Inter { //这时候我们可以创建一个接口让Inner实现,这样我们获取Inner对象的时候就可以用Inter接口来接收了
public void showA();
public void showB();
public void showC();
}
class Outer{
private class Inner implements Inter {
public void showA(){System.out.println("Inner - showA");}
public void showB(){System.out.println("Inner - showA");}
public void showC(){System.out.println("Inner - showA");}
}
public Inner getIner(){
return new Inner();
}
}
- 分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
1. 成员内部类
- 说明: 定义在外部类的成员位置(外部类的方法外),并且没有static修饰
- 成员内部类的创建需要依赖于外部类对象
- 成员内部类可以直接访问外部类的成员
- 当内部类有与外部类重名的变量时,可使用 外部类.this.变量名
class Outer{
//成员变量
private String name = "张彪";
int age = 666;
//成员内部类
class Inner{
int age = 18;
private String str = "是大衰哥!!!";
public void showMsg(){
//可以看出,当内部类有与外部类重名的变量时,可使用 外部类.this.变量名
System.out.println(age); //输出: 18
System.out.println(this.age); //输出: 18
System.out.println(Outer.this.age); //输出: 666
//成员内部类可以直接访问外部类的私有成员
System.out.println(age+ "岁的" + name + str); //输出: 18岁的张彪是大衰哥!!!
}
}
public void Demo(){
Inner inner = new Inner();
inner.showMsg();
}
}
2. 静态内部类
- 说明: 定义在外部类的成员位置,并且有static修饰
- 和静态方法相同,静态内部类只能访问静态成员,静态内部类不需要外部类创建对象就可以使用
- 使用方法: 外部类名.内部类名.成员
class Outer{
//静态成员变量
static String name;
int age;
//静态内部类
static class Inner{
public void saySomething(){
System.out.println(name);
//System.out.println(age); 报错,静态只能访问静态
}
}
}
3. 局部内部类
- 说明: 定义在外部类的局部位置(外部类的方法或作用域内),比如方法中,并且有类名
- 不能被【static】修饰
- 可以直接访问方法的成员
- 可以直接访问局部内部类的成员
- 可以直接访问外部类的成员
- 创建对象要在方法内部或局部类的外部
//外部类
class Outer{
//外部成员变量
String name = "Outer";
//外部类方法
void Demo(){
//外部类成员变量
String name = "Demo";
//局部内部类
class Inner{
//局部内部类成员变量
String name = "Inner";
public void saySomething(String name){
System.out.println(name); //输出: Demo; 可以直接访问方法的成员
System.out.println(this.name); //输出: Inner;可以直接访问局部内部类的成员
System.out.println(Outer.this.name); //输出: Outer;可以直接访问外部类的成员
}
}
//创建对象要在方法内部或局部类的外部
new Inner().saySomething(name);
}
}
4. 匿名内部类
- 说明: 定义在外部类的局部位置,比如方法中,并且没有类名
- 本质上是一个 【对象】,要注意匿名内部类是 【没有类名】 的
- 是一个没有名字的局部内部类
- 是一个一次性使用,用完就扔
- 前提: 存在一个类或者接口,这里的类可以是具体类也可以是抽象类
- 编译之后,会产生一个单独的.class字节码文件
//格式:
new 类名或者接口名{
//重写方法
}
interface Inter{
void show();
}
class Outer{
new Inter(){
@Override
public void show(){
System.out.println(""匿名内部类);
}
}.show(); //因为匿名内部类本质上是 对象,所以可以直接调用方法
//因为匿名内部类本质上是 对象,所以可以被其实现的接口接收
Inter i = new Inter(){
@Override
public void show(){
System.out.println(""匿名内部类);
}
};
i.show();
}
二、lambda表达式
- 说明: 是匿名内部类的简化版,但不是所有匿名内部类都可以用lambda表达式简化,只有 函数式接口 的匿名内部类才可以使用Lambda表达式来进行简化
- 函数式接口: 只有一个抽象方法的接口称为函数式接口
- 格式: (形参列表) -> {方法体}
* - 编译之后,不会生成一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
举个栗子
- 面向对象思想:匿名内部类实现
//面向对象思想
interface inter {
void show(String name);
}
class Outer {
public static void main(String[] args) {
//匿名内部类实现
showMsg("张彪", new inter() {
@Override
public void show(String name) {
System.out.println(name + "是我的好大儿!!!");//输出: 张彪是我的好大儿!!!
}
});
}
public static void showMsg(String name, inter i){
i.show(name);
}
}
-
- 函数式思想:Lambda表达式实现
//函数式思想
interface inter {
void show(String name);
}
class Outer {
public static void main(String[] args) {
//Lambda表达式实现
showMsg("张彪", name -> System.out.println(name + "是我的好大儿啊!!!") );//输出: 张彪是我的好大儿啊!!!
}
public static void showMsg(String name, inter i){
i.show(name);
}
}
Lambda表达式还可以更简洁
- 1. 当方法体只有一句时,可以一起省略 【大括号 {}】 和 语句后面的【分号 ;】
2.当方法体只return一个结果,可以一起省略 【return】、【大括号 {}】和【分号 ;】
3. 当参数只有一个,可以省略【小括号 ()】和【参数类型】
interface inter1 {void show();} //无参、无返回值
interface inter2 {String show();} //无参、有返回值
interface inter3 {void show(String name);} //有参、无返回值
interface inter4 {String show(String name);}//有参、有返回值
class Outer {
public static void main(String[] args) {
String str = "有参";
showMsg1(() -> {
System.out.println("无参、无返回值的Lambda表达式");
});
//当方法体只有一句时,可以一起省略 【大括号 {}】 和 语句后面的【分号 ;】
showMsg1(() -> System.out.println("一起省略 【大括号 {}】 和 语句后面的【分号 ;】的 无参、无返回值的Lambda表达式"));
System.out.println("\n==============================我是分割线==============================\n");
showMsg2(() -> {
return "无参、有返回值的Lambda表达式";
});
//当方法体只return一个结果,可以一起省略 【return】、【大括号 {}】和【分号 ;】
showMsg2(() -> "一起省略 【return】、【大括号 {}】和【分号 ;】的 无参、有返回值的Lambda表达式");
System.out.println("\n==============================我是分割线==============================\n");
showMsg3(str, (String name) -> {
System.out.println(str + "、无返回值的Lambda表达式");
});
//当参数只有一个,可以省略【小括号 ()】和【参数类型】
showMsg3(str, name -> System.out.println("省略【小括号 ()】、【大括号 {}】 和 语句后面的【分号 ;】的 " + str + "、无返回值的Lambda表达式"));
System.out.println("\n==============================我是分割线==============================\n");
//省略 【小括号 ()】、【大括号 {}】 、 语句后面的【分号 ;】、【return】
showMsg4(str, (String name) -> {
return str + "、有返回值的Lambda表达式";
});
showMsg4(str, name -> "省略【小括号 ()】、【大括号 {}】 、 语句后面的【分号 ;】、【return】的" + str + "、有返回值的Lambda表达式");
}
public static void showMsg1(inter1 i) {
i.show();
}
public static void showMsg2(inter2 i) {
String result = i.show();
System.out.println("inter2 返回值:" + result);
}
public static void showMsg3(String name, inter3 i) {
i.show(name);
}
public static void showMsg4(String name, inter4 i) {
String result = i.show(name);
System.out.println("inter4 返回值:" + result);
}
}
方法引用
说明: 特定情况下简化Lambda表达式,使语言的构造更紧凑简洁,减少冗余代码。( 将 Lambda表达式再简写一点)
格式: 类 :: 方法
- 当所有参数都交由函数式接口使用时,可使用方法引用
举个栗子
class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("666");
list.add("777");
list.add("888");
//list集合的所有元素交由【System.out 下的 print() 方法】使用
list.forEach(System.out::print);//输出: 666777888
}
}
三、Math 数学工具类
-
该类的所有方法都是静态的
-
该类被【final】修饰,没有子类
-
该类构造方法被【private】修饰,无法创建对象
-
常用方法:
- double sqrt(double a); 返回 double值的正确舍入的正平方根。
- double abs(double d); 获取传入参数的绝对值
- double ceil(double a) 向上取整
- double floor(double a); 向下取整
- int round(double d) 四舍五入
- int max(int a,int b); 获取最大值
- double pow(double a,double b); 获取第一个参数的第二个参数次幂 2^3
- double random(); 获取一个[0.0,1.0)
举个栗子
class MathTest {
public static void main(String[] args) {
System.out.println("Math.sqrt(num):\t" + Math.sqrt(4)); //计算【4】开平方根; 输出: Math.sqrt(num): 2.0
System.out.println("Math.abs(-4):\t\t" + Math.abs(-4)); //计算【-4】的绝对值; 输出: Math.abs(-4): 4
System.out.println("Math.ceil(4.4):\t" + Math.ceil(4.4)); //【4.4】向上取整; 输出: Math.ceil(4.4): 5.0
System.out.println("Math.floor(4):\t\t" + Math.floor(4)); //【4.4】向下取整; 输出: Math.floor(4): 4.0
System.out.println("Math.round(4.4):\t" + Math.round(4.4)); //【4.4】四舍五入; 输出: Math.round(4.4): 4
System.out.println("Math.pow(4, 4):\t" + Math.pow(4, 4)); //计算【4 的 4 次方】 输出: Math.pow(4, 4): 256.0
System.out.println("Math.random():\t\t" + Math.random()); //获取一个[0.0,1.0) 输出: Math.random(): 0.9625000419745177 【随机数,不是固定的】
System.out.println("Math.max(4, 44):\t" + Math.max(4, 44)); //【4, 44】的最大值 输出:Math.max(4, 44): 44
}
}
四、System 系统工具类
方法:
Properties getProperties(): 获取系统信息
void exit(int a); 退出JVM Bowser/Server 【别用】
long currentTimeMillis(); 获取当前系统时间的毫秒值 主要用来计算某段程序执行时间。
arrayCopy(Object src,int srcOff,Object dest,int destOff,int len); 数组拷贝
Object src: 原数组
int srcOff: 原数组拷贝的起始索引
Object dest:目标数组
int destOff:目标数组拷贝的起始索引
int len: 拷贝的数组元素个数
举个栗子
//举不动了