Java基础(详细)

本文详细介绍了Java的基础知识,包括常用的API,如Scanner、匿名对象、Random、ArrayList、String、static关键字、Arrays工具类、Math类、Object类、Date类、DateFormat类、Calendar类、System类、StringBulider类、包装类以及基本类型与字符串之间的转换。此外,还涵盖了继承与多态的概念,如抽象类、接口、多态、final关键字的使用,以及权限修饰符、内部类的讲解。文章进一步讨论了集合的相关内容,如Collection、Iterator、泛型、数据结构、List集合(ArrayList、LinkedList、Vector)、Set集合(HashSet)。最后,提到了异常处理、多线程、File类与IO流的使用,如BufferedOutputStream、BufferedInputStream、BufferedReader、BufferedWriter、转换流、序列化流、PrintStream,以及JDK8的新特性,如函数式接口、Stream流式编程和方法引用。
摘要由CSDN通过智能技术生成

目录

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();
	}	
}

权限修饰符的使用规则

  1. 外部类:public/(default)
  2. 成员内部类:public/protected/(default)/private
  3. 局部内部类:什么都不能写

局部内部类的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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值