内部类
- 概念:在一个类的内部再定义一个完整的类,当外部类与内部类的属性重名时,优先访问内部类属性
- 分类:成员内部类、静态内部类、局部内部类、匿名内部类
成员内部类
- 成员内部类在类的内部定义,与外部类的变量和方法同级别的类
- 成员内部类可以直接拿到外部类的私有属性
- 成员内部类里不能定义静态成员、可以包含静态常量(final),这个静态常量在不实例化外部类的情况下可以调用
public class Outer{
private int id = 10;
public void out(){
System.out.println("这是外部方法");
}
public class Inner {
static final String XXX = "这是一个静态常量";
public void in(){
System.out.println("这是内部方法");
}
public void getID(){
System.out.println(id);
}
}
}
实例化成员内部类
public class Test {
public static void main(String[] args) {
// 在没有实例化外部类的情况下可调用内部类的静态常量
String xxx = Outer.Inner.XXX;
System.out.println(xxx);
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.getID();
}
}
局部内部类
- 局部内部类就是定义在外部类的方法里面的类,作用范围和创建对象范围仅限于当前方法,不能添加任何修饰符
- 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final,这是JDK1.7的规定,JDK1.8以后,这个final会自动添加,不用我们考虑
public class Outer{
public void method(){
class Inner{
private String str = "一个局部变量";
public void in(){
}
}
}
}
静态内部类
- 非静态内部类需要在外部类存在一个实例时才可以调用,静态内部类可以直接调用,因为没有一个外部类的实例,所以在静态内部类里面不可以直接访问外部类的属性和方法,若想访问,需要创建外部类的对象来调用
public class Outer{
private String name = "xxx";
private int age = 20;
static class Inner{
private String address = "上海";
private String phone = "111";
private static int count = 1000;
public void show(){
Outer outer = new Outer();
System.out.println(outer.name);
System.out.println(outer.age);
System.out.println(address);
System.out.println(phone);
System.out.println(Inner.count);
}
}
}
匿名内部类
- 匿名内部类也就是没有名字的内部类,正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写,但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
- 匿名类就是在实例化类的同时写出方法,不使用引用保存实例
public class Test {
public static void main(String[] args) {
new Outer().method();
}
}
在接口上使用匿名内部类
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口
Thread类的匿名内部类实现
public class Demo {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
}
}
Runnable接口的匿名内部类实现
public class Demo {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
Thread t = new Thread(r);
t.start();
}
}
Object
Object类是所有类的超类,所有类默认继承Object类
getClass()
返回引用中存储的实际对象类型
Student stu = new Student();
Class class = stu.getClass();
hashCode()
返回对象的哈希值
哈希值:根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值
Student stu = new Student();
int hash = stu.hashCode();
toString()
返回该对象的字符串表示,因为默认打印的是类的内存地址,所以通常我们都会重写这个方法,达到输出字符串的目的
public class Student {
private String name;
private int age;
public Student(String name, int age){
this.name = name;
this.age = age
}
public String toString() {
return "name:" + name + "age:" + age;
}
}
Student stu = new Student("张三",20);
String stuInfo = stu.toString();
equals()
比较两个对象地址是否相同,这个方法在String中被重写了,重写后的方法先对比引用地址,如不相同则对比字面值
Student stu1 = new Student();
Student stu2 = new Student();
boolean result = stu1.equals(stu2);
finalize()
垃圾回收方法,由JVM自动调用此方法
- 垃圾对象:没有有效引用指向此对象
- 垃圾回收:由GC销毁垃圾对象,释放数据存储空间
- 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象
- 手动回收机制:使用System.gc();通知JVM执行垃圾回收
String
创建字符串的两种方式及区别
// 第一种创建方式,栈内引用直接指向方法区中的常量池中的值
String str1 = "你好";
// 第二种创建,堆内新建对象,对象指向方法区中的常量池中的值栈内引用指向堆内对象
String str2 = new String("Hello World");
length()
返回字符串长度
String str = "Hello World";
int leng = str.length();
charAt(int index)
返回某个位置的字符
String str = "Hello World";
char c = str.charAt(0);
contains(String str)
判断是否包含某个子字符串,返回布尔值
String str = "Hello World";
boolean result = str.contains("Hello");
toCharArray()
将字符串转换为字符数组返回
String str = "Hello World";
char[] strs = str.toCharArray();
indexOf(String str)
查找str首次出现的下标,返回,如果不存在,返回-1
String str = "Hello World";
int index = str.indexOf("Hello");
// 从第四位开始查找
int index = str.indexOf("Hello",4);
lastIndexOf(String str)
查找字符串在当前字符串中最后一次出现的下标,返回,如果不存在,返回-1;
String str = "Java Hello Java CC Java";
int index = str.lastIndexOf("Java");
trim()
去掉字符串前后空格
String str = " Hello World ";
String str2 = str.trim();
toUpperCase()
将小写转成大写
toLowerCase()
将大写转换成小写
String str = "Hello World";
String str2 = str.toUpperCase();
String str3 = str.toLowerCase();
endsWith(String str)
判断字符串是否以str结尾
startsWith(String str)
判断字符串是否以str开头
String str = "Hello World";
boolean r1 = str.startsWith("Hello");
boolean r2 = str.endsWith("World");
replace(char oldChar,char newChar)
将旧字符串替换成新字符串
String str = "Hello World";
String str2 = str.replace("World","Java");
split(String str)
根据str对字符串进行拆分,返回一个字符串数组
String str = "Hello World Java PHP C,Python|C++";
// 以空格分隔字符串
String[] strs = str.split(" ")
// 以多个符号分隔字符串空格,逗号竖线都可分隔
String[] strs = str.split("[ ,|]")
可变字符串
-
StringBuffer : 可变长字符串,运行效率慢、线程安全
-
StringBuilder : 可变长字符串、运行快、线程不安全
-
StringBuffer和StringBuilder的效率都高于String,都比String节省内存
-
StringBuffer和StringBuilder的用法是一样的,StringBuilder的效率高于StringBuffer
StringBuilder sb = new StringBuilder();
// append()追加
sb.append("Hello World");
// insert()添加
sb.insert(0,"Hello World");
// replace()替换:取前不取后
sb.replace(6,11,"Java");
// delete()删除
sb.delete(6,sb.length());
// 打印
sb.toString();
BigDecimal
- float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,然而,它们没有提供完全精确的结果。但是,商业计算往往要求结果精确,这时候BigDecimal就派上大用场啦。
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("0.9");
// 加
BigDecimal result1 = bd1.add(bd2);
// 减
BigDecimal result2 = bd1.subtract(bd2);
// 乘
BigDecimal result3 = bd1.multiply(bd2);
// 除
BigDecimal result4 = bd1.divide(bd2);
// 因为除不尽会报错,所以这里保留两位小数四舍五入
BigDecimal result5 = bd1.divide(bd2).setScale(2, RoundingMode.HALF_UP)
Date
- Date表示特定的瞬间,精确到毫秒。Date类中的大部分方法都已经被Calendar类中的方法所取代
public static void main(String[] args) {
// 1 创建Date对象
Date date1 = new Date();
System.out.println(date1.toString()); //Sun Sep 19 18:53:23 CST 2021
System.out.println(date1.toLocaleString()); //2021年9月19日 下午6:53:23
// 昨天
Date date2 = new Date(date1.getTime() - (60*60*24*1000));
System.out.println(date2.toLocaleString()); //2021年9月18日 下午6:53:23
// 2 方法after before
boolean b1 = date1.after(date2);
System.out.println(b1); //true
boolean b2 = date1.before(date2);
System.out.println(b2); //false
// 比较compareTo();
int d = date1.compareTo(date1);
System.out.println(d); // 多的为1 少的为 -1
// 比较是否相等 equals()
boolean b3 = date1.equals(date2);
System.out.println(b3); // false
}
Calendar
- Calendar提供了获取或设置各种日历字段的方法
public static void main(String[] args) {
// 1. 创建 Calendar 对象
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toLocaleString());
// 2. 获取时间信息
// 获取年
int year = calendar.get(Calendar.YEAR);
// 获取月 从 0 - 11
int month = calendar.get(Calendar.MONTH);
// 日
int day = calendar.get(Calendar.DAY_OF_MONTH);
// 小时
int hour = calendar.get(Calendar.HOUR_OF_DAY);
// 分钟
int minute = calendar.get(Calendar.MINUTE);
// 秒
int second = calendar.get(Calendar.SECOND);
// 3. 修改时间
Calendar calendar2 = Calendar.getInstance();
calendar2.set(Calendar.DAY_OF_MONTH, x);
// 4. add修改时间
calendar2.add(Calendar.HOUR, x); // x为正就加 负就减
// 5. 补充方法
int max = calendar2.getActualMaximum(Calendar.DAY_OF_MONTH);// 月数最大天数
int min = calendar2.getActualMinimum(Calendar.DAY_OF_MONTH);
}
SimpleDateFormat
- SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类
public static void main(String[] args) throws ParseException {
// 1. 创建对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH-mm-ss");
// 2. 创建Date
Date date = new Date();
// 格式化date(日期→字符串)
String str = sdf.format(date);
System.out.println(str);
// 解析(字符串→时间)
Date date2 = sdf.parse("1948/03/12");
System.out.println(date2);
}
System
- 主要用于获取系统的属性数据和其他操作,构造方法私有的
public static void main(String[] args) {
//arraycopy 复制
//src-原数组 srcPos-从哪个位置开始复制0 dest-目标数组 destPos-目标数组的位置 length-复制的长度
int[] arr = {20, 18, 39, 3};
int[] dest = new int [4];
//System.arraycopy(src, srcPos, dest, destPos, length);
System.arraycopy(arr, 0, dest, 0, 4);
for (int i : dest) {
System.out.println(i);
}
// 返回当前系统时间(毫秒)
System.currentTimeMillis();
// Arrays.copyOf(original, newLength)
}