目录
1、常用的API_1
1.1 Scanner类
Scanner类的功能:可以实现键盘输入数据到程序中
使用步骤:
- 导包 import 包路径.类名称;
- 如果需要使用的目标类和当前类位于同一个包下,则可以省略导包语句不写
- 只有java.lang包下的内容不需要导包,其他的包都需要import语句
- 创建:类名称 对象名=new 类名称()
- 使用:对象名.成员方法名()
import java.util.Scanner; //导包
public class Scanner1 {
public static void main(String[] args) {
//创建
Scanner scanner = new Scanner(System.in);
//获取键盘输入的int数字
int i = scanner.nextInt();
System.out.println("输入的数字是:"+i);
//获取键盘输入的字符串
String str = scanner.next();
System.out.println("键盘输入的字符串是:"+str);
}
}
1.2 匿名对象
匿名对象是只有右边的对象,没有左边的名字和赋值运算:
new 类名称();
匿名对象只能使用惟一的一次,下次再用需要重新创建一个新对象。 如果一个对象只需要使用唯一的一次,推荐使用匿名对象 。
int num=new Scanner(System.in).nextInt();
System.out.print("输入的是:"+num);
1.3 Random类
package bridge;
import java.util.Random;
public class Scanner1 {
public static void main(String[] args) {
//创建
Random r=new Random();
//生成随机数
//nextInt()生成的随机数范围是int范围,包括正负
int num=r.nextInt();
System.out.println("生成的随机数是"+num);
//nextInt(n):带参数的,参数代表了范围,左闭右开区间
System.out.println("生成的随机数是"+r.nextInt(100));
}
}
1.4 ArrayList集合
ArrayList的长度是可以变化的。
常用方法:
- public boolean add(E e)
- public E get(int index)
- public E remove(int index)
- public int size()
//数组:一旦创建,程序运行期间长度不能改变
int[] array=new int[3];
array[0]=1;
array[1]=2;
array[2]=3;
System.out.println(array[0]);
import java.util.ArrayList; //导包
/**
* 对于AArrayList来说,有一个尖括号<E>代表泛型,指的是集合中的元素的类型
* 泛型只能是引用类型,不能是基本类型
* ArrayList直接打印的不是地址值,而是内容,如果集合为空,打印的[]
*/
public class Scanner1 {
public static void main(String[] args) {
//创建
ArrayList<String> list=new ArrayList<>();
System.out.println(list); //[]
//向集合中添加数据
list.add("Julia");
list.add("Julia2");
list.add("Julia3");
System.out.println(list);
//获取集合的长度
System.out.println("集合的长度为"+list.size());
//移除集合中的元素
list.remove(0);
System.out.println(list);
//获取集合中的元素
System.out.println("第2个集合元素是"+list.get(1));
//遍历集合
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
1.5 String类
字符串的特点:
- 字符串的内容永不改变
- 正是因为字符串不可改变,所以字符串是可以共享使用的
- 字符串效果上是char[]字符数组,但是底层原理是byte[]字节数组
创建字符串的常见3+1种方法:
三种构造方法:
- public String();创建一个空白字符串,不会有任何内容
- public String(char[] array);根据字符数组的内容,来创建对应的字符串
- public String(byte[] array);根据字节数组的内容,来创建对应的字符串
一种直接创建:
String str=“Hello”; 右边直接使用双引号(也是字符串对象,即使没有new)
字符串常量池:
字符串的比较方法:
- public boolean equals(Object obj):只有当参数是一个字符串并且值相同时才会是true
- public boolean equalsIgnoreCase(String str):忽略大小写进行比较
字符串的获取相关的方法:
- public int length():获取字符串长度
- public String concat(String str):拼接字符串
- public char charAt(int index):获取指定索引位置的单个字符
- public int indexOf(String str):查找参数字符串的在本字符串首次出现的位置,如果没有则返回-1
字符串的截取方法:
- public String substring(int index):从index到结尾
- public String substring(int begin,int end):左闭右开区间
字符串与转换相关的方法:
- public char[] toCharArray():将当前字符串拆分成字符数组作为返回值
- public byte[] getBytes():获得当前字符串底层的字节数组
- public String replace(charSequence oldString,charSequence newString):将所有出现的老字符串替换成新的字符串,返回替换之后的新字符串
字符串的分割方法:
- public String[] split(String regex):按照参数的规则将字符串分成若干部分
- 注意事项:参数其实是正则表达式。当切割规则是".",要写成"\."
1.6 static静态
一旦用了static关键字,那么这样的内容就不再属于对象自己,而是属于类的,所以凡是本类的对象,都共享同一份。
static修饰成员变量,那么这个变量就不再属于对象自己,而是属于所在的类,多个对象共享同一个数据。
static修饰成员方法时,那么这就是静态方法,静态方法不属于对象,而是属于类。没有static关键字,需要先创建对象才能使用方法。(对于本类当中的静态方法,可以省略类名称进行调用)
注意事项:
- 静态不能直接访问非静态
- 原因:因为在内存中是【先】有的静态内容,【后】有的非静态内容
- 静态方法中不能使用this
- 原因:this代表当前对象,通过谁调用该方法,谁就是当前对象。但是static跟对象没关系
静态内存图:
静态代码块:
特点: 当第一次用到本类时,静态代码块执行唯一一次。
格式:
public class 类名称{
static{
//静态代码块的内容
}
}
典型用途:一次性对静态成员变量进行赋值。
1.7 Arrays工具类
java.utils.Arrays是一个与数组相关的工具类,里面提供了大量的静态方法,用来实现数组常见的操作
常用方法:
- public static String toString(数组):将参数数组变成字符串(按照默认格式:[元素1,元素2,元素3…])
- public static void sort(数组):按照默认升序对数组元素进行排序
- 如果是数组,那么按照从小到大排序
- 如果是字符串,按照字母大小排序
- 如果是自定义类型,那么这个自定义的类需要有Comparable或Comparator接口的支持
int[] intArray={
1,2,3};
String str= Arrays.toString(intArray);
System.out.println(str); //[1, 2, 3]
int[] array={
1,3,2,5,8,7,6};
Arrays.sort(array);
System.out.println(Arrays.toString(array));//[1, 2, 3, 5, 6, 7, 8]
1.8 Math类
常用方法:
- public static double abs(double num):绝对值
- public static double ceil(double num):向上取整
- public static double floor(double num):向下取整
- public static long round(double num):四舍五入
- Math.PI 圆周率
1.9 Object类
Object中的equals方法:
- 基本数据类型,比较的是指
- 引用数据类型,比较的是两个对象的地址值
重写equals方法,比较对象的属性:
问题:
- 隐含着多态,多态的弊端:无法使用子类特有的内容(属性和方法)
- Obj obj=new Person(“Lisa”,20)
- 可以使用向下转型
@Override
public boolean equals(Object obj){
//提高程序效率
if(obj==null){
return false;
}
//提高程序效率
if(obj==this){
return true;
}
if(obj instanceof Person){
//使用向下转型,把obj转换为Person类型
Person p=(Person) obj;
boolean b=this.name.equals(p.name) && this.age==p.age;
return b;
}
return false;
}
当然,也可以用快捷键生成重写的equals和hashcode
补充:Objects类的equals方法:也是对两个对象的比较,但是可以防止空指针异常
String s1="hello";
String s2=null;
Objects.equals(s1,s2); //正确
s2.equals(s1); //空指针异常
1.10 Date类
表示日期和时间的类
把日期转换为毫秒:
- 当前的日期
- 时间原点(0毫秒):1970年1月1日 00:00:00
- 就是计算当前日期到时间原点之前一共经历了多少毫秒
把毫秒转换为日期:
1天=24x60x60秒=86400秒=24x60x60x1000秒=86400000毫秒
注意:中国属于东八区,会把时间增加8个小时:1970年1月1日 08:00:00
public class test {
public static void main(String[] args) {
System.out.println(System.currentTimeMillis());
demo1();//Date类的无参构造
demo2();//Date类的带参构造
demo3();//getTime方法,相当于System.currentTimeMillis()
}
private static void demo3() {
Date date = new Date();
long time = date.getTime();
System.out.println(time);
}
private static void demo2() {
Date date = new Date(0L);
System.out.println(date);
}
private static void demo1() {
Date date = new Date();
System.out.println(date); //Sun Dec 27 15:00:01 CST 2020
}
}
1.10.2 DateFormat类
作用:格式化和解析日期
成员方法:String format(Date date) 按照指定的模式,把Date日期格式化为符合模式的字符串
Date parse(String source)把符合模式的字符串解析为Date日期
DateFormat类是一个抽象类,无法直接创建对象使用,需要用到DateFormat类的子类:SimpleDateFormat
public class test {
public static void main(String[] args) throws ParseException {
demo1(); //使用format将日期转化为文本
demo2(); //使用parse方法将字符串解析为Date类型
}
private static void demo2() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date parse = sdf.parse("2020年12月27日 15:10:50");
System.out.println(parse);
}
private static void demo1() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
Date date = new Date();
String d = sdf.format(date);
System.out.println(date); //Sun Dec 27 15:10:50 CST 2020
System.out.println(d); //2020年12月27日 15:10:50
}
}
1.11 Calendar类(日历类)
是一个抽象类,提供了很多操作日历字段的方法
无法直接创建对象使用,里面有一个静态方法getInstance(),返回该类的子类对象
public class test {
public static void main(String[] args) throws ParseException {
demo1(); //get方法,获取指定日历字段的值
demo2();//set方法设置指定字段
demo3(); //add 将指定字段增加或减少值
demo4(); //getTime 把日历对象转换为日期对象
}
private static void demo4() {
Calendar c = Calendar.getInstance();
Date time = c.getTime();
System.out.println(time);
}
private static void demo3() {
Calendar c = Calendar.getInstance();
c.add(Calendar.YEAR,1);
System.out.println(Calendar.YEAR);
}
private static void demo2() {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR,9999);
System.out.println(Calendar.YEAR);
//同时设置年月日
c.set(9999,9,9);
}
private static void demo1() {
Calendar c = Calendar.getInstance();
int Year = c.get(Calendar.YEAR); //可以用类名直接调用,说明是静态变量
int Month = c.get(Calendar.MONTH);
System.out.println(Year);
System.out.println(Month); //西方的月份为0-11,东方为1-12
}
}
1.12 System类
两个常用静态方法:
- System.currentTimeMillis()
- arrayCopy(Object src,int srcPos,Object dest,int destPos,int length)
public class test {
public static void main(String[] args) throws ParseException {
demo1(); //System.currentTimeMillis()
demo2();//
}
private static void demo2() {
int[] src={
1,2,3,4,5};
int[] dest={
6,7,8,9,10};
System.arraycopy(src,0,dest,0,3);
System.out.println(Arrays.toString(dest));
}
private static void demo1() {
long start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
long end = System.currentTimeMillis();
System.out.println("程序执行用时"+(end-start)+"毫秒");
}
}
1.13 StringBulider类
StringBulider的常用方法:
- append():添加任意类型的数据,并返回对象本身
- toString():将当前StringBulider对象转换为String对象
public class test {
public static void main(String[] args) throws ParseException {
demo1(); //StringBulider的空参构造方法
demo2();//StringBulider的带参构造方法
dem03(); //append添加数据
demo4(); //将String变成StringBulider
demo5(); //将StringBulider变成String
}
private static void demo5() {
StringBuilder bu = new StringBuilder("abc");
String str = bu.toString();
System.out.println(str);
}
private static void demo4() {
String str="hello";
StringBuilder bu = new StringBuilder(str);
bu.append(1);
System.out.println(bu);
}
private static void dem03() {
StringBuilder sb = new StringBuilder();
sb.append("abc");
System.out.println("sb3:"+sb);
}
private static void demo2() {
StringBuilder sb = new StringBuilder("abc");
System.out.println("sb2:"+sb);
}
private static void demo1() {
StringBuilder sb = new StringBuilder();
System.out.println("sb1:"+sb);
}
}
1.14 包装类
装箱:把基本类型的数据,包装到包装类中(基本类型)
拆箱:在包装类中取出基本类型的数据(包装类->基本类型数据)
public class test {
public static void main(String[] args) throws ParseException {
//装箱
Integer i1 = new Integer(1);
System.out.println(i1);
Integer i2 = new Integer("1");
System.out.println(i2);
Integer i3 = Integer.valueOf(1);
System.out.println(i3);
Integer i4 = Integer.valueOf("1");
System.out.println(i4);
//拆箱
int i5 = i1.intValue();
System.out.println(i5);
}
}
1.14.2基本类型与字符串之间的转换
基本类型->字符串
- 基本类型的值+"",最简单的方法(工作中常用)
- 包装类的静态方法 toString(参数),不是Object类的toString()的重载
- String类的静态方法valueOf(参数)
字符串->基本类型
- 使用包装类的静态方法,parseXXX(“字符串”)
- Integer类:static int parseInt(String str)
- Double类:static double parseDouble(String str)
public class test {
public static void main(String[] args) throws ParseException {
//基本类型->字符串
int num=100;
String s1=num+"";
System.out.println(s1+100); //100100
String s2=Integer.toString(num);
System.out.println(s2+100);//100100
String s3=String.valueOf(num);
System.out.println(s3+100);//100100
//字符串->基本类型
String s4="1";
int i = Integer.parseInt(s4);
System.out.println(i+100); //101
}
}
2、继承与多态
2.1 继承
继承主要解决的问题是共性抽取。
Java是单继承的
在继承的关系中,“子类就是一个父类”——is的关系
//定义父类的格式:(一个普通的类的定义)
public class 父类名称{
}
//定义子类的格式
public class 子类名称 extends 父类名称{
}
在父子类的继承中,如果成员变量重名,则创建子类对象时,访问有两种方式:
- 直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找
Zi zi=new Zi();
zi.num;//等号左边是Zi zi,因此num用的是子类的成员变量的值
- 间接通过成员方法访问成员变量:方法属于谁,就优先用谁,没有则向上找
在父子类的继承关系中,创建子类对象,访问成员方法的规则:创建的对象是谁,就优先用谁,没有则向上找
重写/覆盖(Override):
在继承关系中,方法名称一样,参数列表一样
super关键字的三种用法:
- 在子类的成员方法中,访问父类的成员变量
- 在子类的成员方法中,访问父类的成员方法
- 在子类的构造方法中,访问父类的构造方法
this关键字的三种用法:
- 在本类的成员方法中,访问本类的成员变量
- 在本类的成员方法中,访问本类的另一个成员方法
- 在本类的构造方法中,访问本类的另一个构造方法
super与this关键字图解:
Java继承的三个特点:
- Java是单继承的,一个类的直接父类只能有唯一一个
- Java语言可以多级继承。有爷爷
- 一个子类的直接父类是唯一的(你妈的吃饭方法,你爸爸有吃饭方法,你到底继承哪一个,不能两个一起继承),但是一个父类可以拥有多个子类
2.2 抽象类
要我们计算图形的面积,我们没法计算,因为太"抽象"了,但是当我们说到求具体图形的面积,我们就知道了——具体。
如果父类当中的方法不确定如何进行方法体实现,那么这就应该是一个抽象方法。
抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束
抽象类:抽象方法所在的类必须是抽象类
public class class Animal{
//这是一个抽象方法,代表吃东西,但是吃什么,不确定
public abstract void eat();
//普通方法
public void normal();
}
如何使用抽象类和抽象方法:
- 不能直接创建抽象类
- 必须用一个子类来继承抽象类
- 子类必须覆盖重写父类的所有抽象方法
- 创建子类对象使用
发红包案例:
群主发普通红包,某群有多名成员,群主将红包平均分成n份,让成员取。成员领取红包后,保存到成员余额。
User.java
package test;
public class User {
private String name;
private int money;
public User() {
}
public User(String name, int money) {
this.name = name;
this.money = money;
}
//展示余额
public void show(){
System.out.println("我是"+name+",我还剩"+money+"元。");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
Manger.java
package test;
import java.util.ArrayList;
//群主类
public class Manger extends User{
public Manger() {
}
public Manger(String name, int money) {
super(name, money);
}
//发红包
public ArrayList<Integer> send(int totalMoney,int count){
//首先需要一个集合来存红包
ArrayList<Integer> redList = new ArrayList<>();
//首先看一下余额
int leftMoney = this.getMoney();
if(leftMoney<totalMoney){
//余额不足
System.out.println("余额不足!");
return redList; //返回空集合
}
//扣钱
this.setMoney(this.getMoney()-totalMoney);
//发红包
int avg=totalMoney/count;
int mod=totalMoney%count;
//剩下零头包在最后一个红包中
//塞红包
for (int i = 0; i < count; i++) {
if(i!=count-1){
redList.add(avg);
}
redList.add(mod+avg);
}
return redList;
}
}
Member.java
package test;
import java.util.ArrayList;
import java.util.Random;
public class Member extends User {
public Member() {
}
public Member(String name, int money) {
super(name, money);
}
public void receive(ArrayList<Integer> redList){
//从多个红包中抽一个给自己
int index=new Random().nextInt(redList.size());
int delta=redList.get(index);
this.setMoney(this.getMoney()+delta);
}
}
2.4 接口
接口就是一种公共规范标准。只要符合规范标准,就可以通用。
接口是一种引用数据类型,最重要的内容就是抽象方法。
接口使用步骤:
- 接口不能直接使用,必须有一个实现类来实现接口
- 接口必须覆盖重写接口中所有的抽象方法
- 创建实现类对象使用
public interface MyInterface{
//抽象方法
public abstract void method1();
//默认方法
public default void method2(){
System.out.println("这是一个新添加的默认方法");
}
//静态方法
public static void method3(){
System.out.println("这是接口的静态方法");
}
}
public class MyInterfaceImpl implements MyInterface{
@Override
public void method1(){
System.out.println("实现类实现了接口的抽象方法");
}
@Override
public default void method2(){
//实现类也可以覆盖重写默认方法
System.out.println("这是一个新添加的默认方法");
}
}
public class Main{
public static void main(String[] args){
MyInterfaceImpl mii=new MyInterfaceImpl();
mii.method1(); //实现抽象方法
mii.method2(); //实现默认方法
//通过接口名称直接调用静态方法
MyInterface.method3();
}
}
从Java 9开始,接口中允许定义私有方法:
- 普通私有方法,解决多个默认方法之间代码重复问题
- 静态私有方法,解决多个静态方法之间代码重复问题
接口中也可以定义"成员变量",但必须使用public static final三个关键字进行修饰
从效果上看,这其实就是接口的【常量】
注意事项:
- 接口中的常量,可以省略public static final,但是不写也是这样。
- 接口中的常量,必须进行赋值,不能不赋值。
- 接口中的常量的名称,使用完全大写的字母,用下划线进行分割
- 接口不能有静态代码块和构造方法
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
- 如果实现类没有覆盖重写所有的抽象方法,那该类就是抽象类
- 如果实现类所实现的多个接口中,存在重复的抽象方法,那么只需覆盖重写一次(你妈妈叫你去吃饭,你爸爸叫你吃面,你可以选择吃饭或者吃面,或者吃其他的)
- 如果实现类所实现的多个接口中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行重写
- 一个类如果直接父类当中的方法和接口当中的默认方法产生了冲突,优先使用父类当中的方法
2.5 多态
其实就是一句话:父类引用指向子类对象
格式:
父类名称 对象名=new 子类名称();
接口名称 对象名=new 实现类名称();
使用多态的好处:
对象的向上转型和向下转型:
向上转型一定是安全的,但是也有一个弊端:
对象一旦向上转型为父类,那么就无法调用子类原本的内容。
解决方法:对象的向下转型
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
//子类特有方法
public void play(){
System.out.println("抓老鼠");
}
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("吃骨头");
}
//子类特有的方法
public void play(){
System.out.println("汪汪汪");
}
}
public class test {
public static void main(String[] args) {
Animal animal=new Cat();
animal.eat();
animal.play(); //错误
//向下转型进行还原
Cat cat=(Cat)animal;
cat.play();
}
}
如何才能知道一个父类引用对象,本来是什么子类?
方法:instanceof
public class test {
public static void main(String[] args) {
Animal animal=new Cat();
animal.eat();
if(animal instanceof Dog){
Dog dog=(Dog)animal;
dog.play();
}
if(animal instanceof Cat){
Cat cat=(Cat)animal;
cat.play();
}
}
}
2.6 final关键字
final代表最终的,不可变的
常见的四种用法:
- 修饰类:当前这个类不能有任何的子类(太监类)
- 如果一个类是final的,那么其中的所有成员方法都无法进行覆盖重写
- 修饰方法:这个方法是最终方法,不能被覆盖重写
- abstract和final不能同时使用,矛盾
- 修饰成员变量:变量不可变
- 由于成员变量有默认值,所以用了final之后必须手动赋值,不会给默认值
- 要么直接赋值,要么通过构造方法赋值
- 修饰局部变量:一次赋值,终身不变
- 对于基本类型,不可变指的是数据不可变
- 对于引用类型,不可变指的是变量当中的地址值不可变,但是值可以变
//修饰类:
public final class MyClass{
}
//修饰方法:
public class MyClass{
public final void method(){
System.out.println("hello");
}
}
//修饰局部变量
public class test {
public static void main(String[] args) {
final int num=100;
System.out.println(num);
num=200; //错误!
}
}
//修饰成员变量
public class Person {
private final int a=100; //使用直接赋值
}
public class Person {
private final int a; //使用构造方法赋值
public Person(){
a=100;
}
public Person(int a){
this.a=a;
}
}
2.7 四种权限修饰符
2.8 内部类
如果一个事物的内部包含另一个事物,那么就是一个类内部包含另一个类
分类:
- 成员内部类:定义在一个类的内部
- 如何使用成员内部类:
- 间接方式:在外部类的方法中,使用内部类,然后main只是调用外部类方法,里面间接调用了内部类的方法
- 直接方式:外部类名称.内部类名称 对象名=new 外部类名称().new 内部类名称();
- 如何使用成员内部类:
- 局部内部类(匿名内部类):定义在一个类中的方法的内部
- 只有当前所属的方法才能使用他,出了这个方法外面就不能使用了
注意:内用外,随意访问,但是外用内,一定需要内部类对象
成员内部类:
public class Person {
//外部类
private String name; //外部类的成员变量
public class Heart{
//成员内部类
public void beat(){
//成员内部类的方法
System.out.println("心脏跳动..");
System.out.println("我叫"+name); //成员内部类可以直接使用外部类的成员变量
}
}
public void method(){
//外部类的方法
System.out.println("外部类的方法");
new Heart().beat(); //间接方式使用成员内部类
}
}
//Main.java
public class test {
public static void main(String[] args) {
//使用间接方法调用成员内部类中的方法
Person p=new Person();
p.method();
//直接方法调用成员内部类中的方法
Person.Heart h=new Person().new Heart();
h.beat();
}
}
内部类的同名变量访问:
public class Outer {
int num=10;
public class inner{
int num=20;
public void method(){
int num=30;
System.out.println(num); //30 成员变量,就近原则
System.out.println(this.num); //成员内部类的成员变量
System.out.println(Outer.this.num); //外部类的成员变量
}
}
}
局部内部类:
public class Outer{
private int num=10;
public void outerMethod{
class Inner{
//局部内部类
int num=10;
public void methodInner(){
//局部内部类方法
System.out.println(num); //10
}
}
Inner inner=new Inner(); //只有当前所属的方法才能使用他
inner.methodInner();
}
}
权限修饰符的使用规则:
- 外部类:public/(default)
- 成员内部类:public/protected/(default)/private
- 局部内部类:什么都不能写
局部内部类的final问题:
public class MyOuter{
//int num=10; //所在方法的局部变量
final int num=10;
class MyInner{
public void methodInner(){
System.out.println(num);
}
}
}
局部内部类,如果希望访问所在方法的成员变量,那么这个成员变量必须是【有效final的】
备注:从java 8+开始,只要局部变量事实不变,那么final就可以省略。
原因:
- new出来的对象是在堆内存中的
- 局部变量是跟着方法走的,在栈内存中
- 方法运行结束后,立即出栈,局部变量就会立刻消失
- 但是new出来的对象会在堆内存中持续存在,直到垃圾回收消失
匿名内部类:
如果接口的实现类(或者是父类的子类)只需要执行一次,那么就可以省略实现类的定义,用匿名内部类。
public