10:内部类与常用类 || 别人所写好的正是我们要学习的
内部类与常用类
一、内部类
1. 内部类的分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
2. 什么是内部类
概念:在一个类的内部再定义一个完整的类
class Outer{
class Inner{
}
}
package xyz.qianfeng.innerClass;
//身体
public class Body {
//头部 内部类也会生成class文件 Body$Header.class
class Header{
}
}

特点:
- 编译之后可生成独立的字节码文件。
- 内部类可直接访问外部类的私有成员,而不破坏封装。
- 内部类可以为外部类提供必要的内部功能组件。
3. 成员内部类
-
在类的内部定义,与实例变量、实例方法同级别的类。
-
外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
或
Outer.Inner inner = new Outer().new Inner();
-
当外部类、内部类存在重名属性时,会优先访问内部类属性。若要访问外部类的同名属性,需要加: 外部类类名.this.属性名
Outer.this.name
-
成员内部类里是不能定义静态成员的,会报错,但是可以定义静态常量
private static String country = "中国"; 会报错
private static final String country = "中国"; 不会报错
package xyz.qianfeng.innerClass;
//外部类
public class Outer {
//实例变量
private String name = "zhangsan";
private int age = 10;
//成员内部类 前面也可以加修饰符 private public等
class Inner{
private String address = "北京";
private String phone = "110";
private String name = "lisi";//当外部类、内部类存在重名属性时,会优先访问内部类属性
// private static String country = "中国"; // 成员内部类里是不能定义静态成员的,会报错,但是可以定义静态常量
private static final String country = "中国"; //静态常量不会报错
//方法
public void show(){
//打印外部类的属性
System.out.println(Outer.this.name);
//当外部类、内部类存在重名属性时,会优先访问内部类属性,
// 若要打印外部类的name,需要加外部类 Outer.this.name
System.out.println(name);//跟外部类同名的话,这个会优先打印为内部类的
System.out.println(Outer.this.age);
//打印内部类的属性
System.out.println(address);
System.out.println(phone);
}
}
}
package xyz.qianfeng.innerClass;
public class TestOuter {
public static void main(String[] args) {
// //1. 先创建外部类对象
// Outer outer = new Outer();
// //2. 创建成员内部类对象
// Outer.Inner inner = outer.new Inner();
// 上边两步可以合成一步
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}

4. 静态内部类
不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员,相当于外部类,普通类包含什么,静态内部类就可以包含什么。即静态内部类和外部类是同一级别。
package xyz.qianfeng.innerClass.demo02;
//外部类
public class Outer {
private String name = "2123";
private int age = 18;
//静态内部类:级别和外部类相同 只有内部类可以用static修饰形成静态内部类 其他类不可以使用该关键字
static class Inner{
private String address = "上海";
private String phone = "111";
//可以包含静态成员
private static int count = 10;
public void show(){
//调用外部类的属性方法,不能直接访问,需要实例化
//1. 创建外部类对象
Outer outer = new Outer();
//2. 调用外部类对象的属性
System.out.println(outer.age);
System.out.println(outer.name);
//调用静态内部类的属性和方法,直接调用
System.out.println(address);
System.out.println(phone);
//调用静态内部类的静态属性,直接:类名.属性名
System.out.println(Inner.count);
}
}
}
package xyz.qianfeng.innerClass.demo02;
public class Test {
public static void main(String[] args) {
//直接创建静态内部类对象
Outer.Inner inner = new Outer.Inner();
inner.show();
}
}
5. 局部内部类
局部变量是定义在方法中的,同理,局部内部类也是定义在外部类方法中,作用范围和创建对象范围仅限于当前方法。
局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final。
局部内部类的使用范围是有限的,只能在当前方法中使用。
package xyz.qianfeng.innerClass.demo03;
//外部类
public class Outer {
private String name = "liu";
private int age = 35;
public void show(){
//定义局部变量
String address = "成都"; //默认加了final 不能再对这个进行修改
//局部内部类 跟局部变量一样,前面不能加任何修饰符
class Inner{
private String phone = "15165564";
private String email = "jdieahdeh@hfadf.com";
// private static int count = 100;会报错 不能是静态的
private final static int count = 100; //静态常量不会报错
public void show2() {
//访问外部类的属性
System.out.println(name);//如果show方法是静态的 则不能直接访问外部类的属性,需要实例化外部类
System.out.println(Outer.this.age);//这两条相当于默认省略了 Outer.this
//访问内部类的属性
System.out.println(phone);
System.out.println(this.email);//相当于省略了this.
//访问局部变量 jdk1.7要求 :变量必须是常量final,jdk1.8 会自动添加final上去 所以不能再对其进行修改
System.out.println(address);//其实这里的address已经写死为常量 “成都”
}
}
//需要创建局部内部类对象
Inner inner = new Inner();
inner.show2();
}
}
package xyz.qianfeng.innerClass.demo03;
public class Test {
public static void main(String[] args) {
//局部内部类只能在对应的方法内使用,所以需要先创建外部类
Outer outer = new Outer();
outer.show();
}
}
6. 匿名内部类
没有类名的局部内部类(一切特征都与局部内部类相同)。
必须继承一个父类或者实现一个借口的情况下使用较多。
定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
优点:减少代码量。
缺点:可读性较差。
package xyz.qianfeng.innerClass.demo04;
//接口
public interface USB {
//服务
void service();
}
package xyz.qianfeng.innerClass.demo04;
public class USBImpl implements USB {
@Override
public void service() {
System.out.println("链接电脑成功,鼠标开始工作");
}
}
package xyz.qianfeng.innerClass.demo04;
public class Test {
public static void main(String[] args) {
//创建接口类型的变量
// USB usb = new USBImpl();
// usb.service();
//局部内部类
// class FenShan implements USB{
// @Override
// public void service() {
// System.out.println("链接电脑成功,这是一个风扇开始工作");
// }
// }
// //使用局部内部类创建对象
// USB usb = new FenShan();
// usb.service();
//因为局部内部类只使用一次,所以出现了匿名内部类
//使用匿名内部类优化 相当于创建了一个局部内部类
//匿名内部类的名字我们看不到,但是实际编译是有一个class文件的 叫做: Test$1.class
USB usb = new USB() {
@Override
public void service() {
System.out.println("链接电脑成功,这是一个风扇开始工作");
}
};
usb.service();
}
}
二、Object类
超类、基类,所有类的直接或间接父类,位于继承树的最顶层。俗称(祖宗类)。
任何类,如没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继承。
Object类中所定义的方法,是所有对象都具备的方法。
Object类型可以存储任何对象。
- 作为参数,可接受任何对象。
- 作为返回值,可返回任何对象。

1. getClass() 方法
public final Class<?> getClass(){
}
返回当前对象的类类型,即返回引用中存储的实际对象类型。
应用:通常用于判断两个引用中实际存储对象类型是否一致。
package xyz.qianfeng.object;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package xyz.qianfeng.object;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",22);
//getClass方法
//判断s1和s2是不是统一类型
Class class1 = s1.getClass();
Class class2 = s2.getClass();
if (class1 == class2){
System.out.println("s1和s2是属于同一个类型");
}else{
System.out.println("s1和s2不属于同一个类型");
}
}
}
2. hashCode() 方法
publie int hashCode(){
}
返回该对象的哈希码值。
哈希值根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值。
一般情况下相同对象返回相同哈希码。
package xyz.qianfeng.object;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",22);
//hashCode方法
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Student s3 = s1;
System.out.println(s3.hashCode());//s3和s1相同,指向的是同一个对象
}
}

3. toString() 方法
public String toString(){
}
返回该对象的字符串表示(表现形式)。
可以根据程序需求覆盖该方法,如:展示对象各个属性值。
package xyz.qianfeng.object;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",22);
//toString 方法
System.out.println(s1.toString());
System.out.println(s2.toString());
}
}

可以发现@后面的hash值跟hashCode()方法执行出来的hash值不一样:

但其实经过计算器计算发现这两个值是一样的,只不过前者为16进制 后者为10进制。
计算器打开快捷键:Win+R 输入:calc

但有些时候 我们并不想看到原始的toString显示的东西,所以我们需要重写toString方法。
package xyz.qianfeng.object;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重写 手动重写
// @Override
// public String toString(){
// return name+":"+age;
// }
//重写toString方法 快捷键
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
重写快捷键:Alt+Insert 点击toString

4. equals() 方法
public boolean equals(Object obj){
}
默认实现为(this == obj),比较两个对象地址是否相同。
package xyz.qianfeng.object;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",22);
//equals方法:判断两个对象是否相等 this == obj 其实比较的是两个对象的地址 如果相同 返回ture 不同 返回false
Student s3 = s1;
System.out.println(s1.equals(s2));//false
Student s4 = new Student("xiaoming",17);
Student s5 = new Student("xiaoming",17);
System.out.println(s4.equals(s5));//false
System.out.println(s1.equals(s3));//true
}
}
可进行覆盖,比较两个对象的内容是否相同。
equals() 方法覆盖步骤:
- 比较两个引用是否指向同一个对象
- 判断obj是否为null
- 判断两个引用指向的实际对象类型是否一致
- 强制类型转换
- 依次比较各个属性值是否相同
package xyz.qianfeng.object;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// @Override
// public String toString(){
// return name+":"+age;
// }
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写 equals方法
@Override
public boolean equals(Object obj) {
//1. 判断两个对象是否是同一个引用
if (this == obj){
return true;
}
//2. 判断obj是否为null
if (obj == null){
return false;
}
//3. 判断是否属于一个类型
// if (this.getClass() == obj.getClass()){ //方法一 不常用
//
// }
//instanceof 可以判断对象是否是某种类型
if(obj instanceof Student){//方法二
//4. 强制类型转换
Student s = (Student)obj;
//5. 比较属性
if (this.name.equals(s.getName()) && this.age == s.getAge()){
//这里之所以能用equals比较两个字符串是否相等 是因为在String类里sun公司已经重写了equals方法用来比较字符串的内容。
//基本上sun公司所有写好的类都重写了equals方法。
return true;
}
}
return false;
}
}
package xyz.qianfeng.object;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("aaa",20);
Student s2 = new Student("bbb",22);
//equals方法:判断两个对象是否相等 this == obj 其实比较的是两个对象的地址 如果相同 返回ture 不同 返回false
System.out.println(s1.equals(s2));//false
Student s3 = s1;
Student s4 = new Student("xiaoming",17);
Student s5 = new Student("xiaoming",17);
System.out.println(s4.equals(s5));//true
System.out.println(s1.equals(s3));//true
}
}

5. finalize() 方法
当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
垃圾对象:没有有效引用指向此对象时,为垃圾对象。
垃圾回收:由GC销毁垃圾对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc();通知JVM执行垃圾回收。
但其实这个方法在后边已经慢慢删除了,过时了。
package xyz.qianfeng.object;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重写finalize
@Override
protected void finalize() throws Throwable {
System.out.println(this.name+"对象被回收了");
}
}
package xyz.qianfeng.object;
public class TestStudent2 {
public static void main(String[] args) {
// Student s1 = new Student("aaaa",12);
// Student s2 = new Student("bbbb",12);
// Student s3 = new Student("cccc",12);
// Student s4 = new Student("dddd",12);
// Student s5 = new Student("eeee",12);
new Student("aaaa",12);
new Student("bbbb",12);
new Student("cccc",12);
new Student("dddd",12);
new Student("eeee",12);
//告诉JVM要回收垃圾
System.gc();
System.out.println("回收垃圾");
}
}

三、包装类
1. 什么是包装类
基本数据类型所对应的引用数据类型。
八种四类的基本数据类型,这八种基本数据类型并没有什么可以直接使用的方法,除了用运算符做一些操作。而且基本数据类型是存放在栈中的,有了包装类之后,将存放在堆中,在栈中引用。
为了能对基本数据类型进行一些方法上的操作,sun公司做了这些基本数据类型对应的引用数据类型,叫做基本数据类型的包装类。
Object可统一所有数据,包装类的默认值是null;(引用类型的默认值都为null)
这八个基本数据类型对应的引用类型如下:
| 基本数据类型 | 包装类型 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Doule |
| boolean | Boolean |
| char | Characte |
- Byte:

- Character

- Double

- Integer

- Long

- Float

- Short

- Boolean

2. 类型转换与装箱、拆箱
装箱:将基本类型转换为引用类型的过程。
拆箱:将引用类型转换为基本类型的过程。
8种包装类提供不同类型间的转换方式:
-
Number父类中提供的6个共性方法。这六个方法可以用来拆箱,将引用类型转换为基本类型。


-
parseXXX()静态方法。可以实现字符串和基本类型之间的转换。
-
valueOf() 静态方法。可以实现基本类型转换为引用类型,即装箱。
注意:
- 需要保证类型兼容,否则抛出NumberFormatException异常。
1.装箱和拆箱演示:
package xyz.qianfeng.baozhuang.demo01;
import xyz.oop.demo11.Outer;
public class Demo01 {
public static void main(String[] args) {
//类型转换:装箱,将基本类型转换为引用类型的过程
int num1 = 18;//基本类型
//使用Integer类创建对象
Integer integer1 = new Integer(num1);//方法1
Integer integer2 = Integer.valueOf(num1);//方法2
System.out.println("装箱");
System.out.println(integer1);
System.out.println(integer2);
//类型转换:拆箱,引用类型转换为基本类型
Integer integer3 = new Integer(100);
int num2 = integer1.intValue();
System.out.println("拆箱");
System.out.println(num2);
//以上的装箱和拆箱都是jdk1.5之前的方法,
//jdk1.5 之后 ,提供自动装箱和拆箱,但其实背后是编译器自动使用了上边手动装箱拆箱的方法。可以在class文件中查看。
int age = 30;
//自动装箱
Integer integer4 = age;
System.out.println("自动装箱");
System.out.println(integer4);
//自动拆箱
int age2 = integer4;
System.out.println("自动拆箱");
System.out.println(age2);
}
}
右键class文件,打开方式选择IDEA后 会自动将二进制文件反编译为Java代码:

对比发现:自动装箱和拆箱的背后是编译器自动使用了手动装箱拆箱的方法。
2.字符串与基本数据类型的转换演示:
package xyz.qianfeng.baozhuang.demo01;
public class Demo02 {
public static void main(String[] args) {
//基本类型和字符串之间的转换
//1. 基本类型转换为字符串
int n1 = 15;
//方法1:使用+号
String s1 = n1 + "";
//方法2:使用Integer中的toString()方法
String s2 = Integer.toString(n1);//普通toString()
String s3 = Integer.toString(n1,16);//重载toString() 加上进制 还有直接转为几进制的toString()方法
System.out.println(s2);
System.out.println(s3);
//2. 字符串转换为基本类型
String str = "150";//如果这里不是数字 转换会报错 数字格式化错误
//使用Integer.parseXXX();
int n2 = Integer.parseInt(str);
System.out.println(n2);
//boolean 字符串形式转换成基本类型,只有“true”可以转换为true 只要非“true”就会转换为false
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
String str3 = "abx";
boolean b2 = Boolean.parseBoolean(str3);
System.out.println(b2);
}
}

3. 整数缓冲区
Java预先创建了256个常用的整数包装类型对象。
之所以使用整数缓存区,是因为在实际应用当中对常用的数字创建好之后方便复用,节省空间。
面试题:
package xyz.qianfeng.baozhuang.demo01;
public class demo03 {
public static void main(String[] args) {
//面试题
Integer integer1 = new Integer(100);
Integer integer2 = new Integer(100);
System.out.println(integer1 == integer2);//false
Integer integer3 = 100;//自动装箱 调用的Integer.valueof(100)
Integer integer4 = 100;
System.out.println(integer3 == integer4);//true
Integer integer5 = 200;//自动装箱 调用的Integer.valueof(200)
Integer integer6 = 200;
System.out.println(integer5 == integer6);//false
//进入valueOf方法的源码查看,发现有个IntegerCache,即Integer缓冲区 它的最小值low为-128 最大值high为127
// 创建了一个 high-low+1 = 256 长度的数组 在堆空间中 保存的数字为-128~127之间的数字
// 而 integer3 和 integer4 在创建的时候只是从上边已经创建好的数组中取值为100的地址,所以两个引用取到的值都是数组中那个100,地址相同
// 而 integer5 和 integer6 在数组中找的时候没有找到200,因为最大值为127,而源码中在数组中找不到的时候就会 new Integer(200);
}
}
四、String类
1. String
字符串是常量,创建之后不可改变。
字符串字面值存储在字符串池(常量池)中,可以共享。(字符串池就在方法区中,不同jdk版本不同)。
学到这里,内存中至少有了:栈、堆、方法区。方法区在不同版本称呼不同,jdk1.8之后叫元空间,1.8之前叫永久代。
快捷键:win+R 输入mspaint 打开画图工具。
字符串赋值方法:
- String s = "Hello";//产生一个对象,字符串池中存储。
- String s = new String(“Hello”);//产生两个对象,堆、池中各存储一个。
package xyz.qianfeng.baozhuang.demo01;
public class demo04 {
public static void main(String[] args) {
//字符串创建方式一:
String name = "hello";//"hello" 常量存储在字符串池
name = "张三";
//"张三"赋值给name,并没有修改原来的数据,而是重新开辟了一个空间,原来的“hello”如果没人用就成垃圾了。
// 所以说字符串创建之后不可改变。
String name2 = "张三";
//程序会去常量池里寻找有无“张三”,有的话把地址给name2
//这时候name1和name2指向的是同一个地址,实现了字符串的共享。
//字符串的另一种创建方式:使用new String
String str = new String( "Java是最好的编程语言。");
//这样创建会浪费空间,存在两个对象,一个在堆中,一个在常量池,
// 但是实际执行的时候,栈中的str指向堆中的“Java”,而堆中的对象指向常量池中的“Java”
//面试题
String str1 = new String( "Java");
String str2 = new String( "Java");
System.out.println(str1 == str2);//false, == 比的是地址 所以字符串内容的比较用equals
System.out.println(str1.equals(str2));//true
}
}

2. 常用方法
- public int length() : 返回字符串的长度
- public char charAt(int index) : 根据下标获取字符
- public boolean contains(String str) : 判断当前字符串中是否包含str
- public char[] toCharArray() : 将字符串转换成数组
- public int indexOf(String str) : 查找str首次出现的下标,存在,则返回该下标;不存在,则返回-1
- public int lastIndexOf(String str) : 查找字符串在当前字符串中最后一次出现的下标索引。
- public String trim() : 去掉字符串前后的空格
- public String toUpperCase() : 将小写转成大写
- public boolean endWith(String str) : 判断字符串是否以str结尾
- public String replace(char oldChar,char newChar) : 将旧字符串替换成新字符串
- public String[] split(String str) : 根据str做拆分
- 补充方法:
- equals、compareTo 用来比较大小
- subString(index) 将一个字符串从下标为index处截取,只取后面的
package xyz.qianfeng.baozhuang.demo01;
import java.util.Arrays;
import java.util.Locale;
public class demo05 {
public static void main(String[] args) {
//字符串方法的使用
//1. length() 返回字符串的长度
//2. charAt(int index) 返回某个位置的字符
//3. contains(String str) 判断是否包含某个字符串
String content = "java是世界上java最好的编程语言,java真香";
System.out.println(content.length());//空格也算一个字符
System.out.println(content.charAt(content.length()-1));
System.out.println(content.contains("java"));
System.out.println(content.contains("PHP"));
System.out.println("=====================================");
//字符串方法的使用
//4. public char[] toCharArray() : 将字符串转换成数组
//5. public int indexOf(String str) : 查找str首次出现的下标,存在,则返回该下标;不存在,则返回-1
//6. public int lastIndexOf(String str) : 查找字符串在当前字符串中最后一次出现的下标索引。
System.out.println(Arrays.toString(content.toCharArray()));
System.out.println(content.indexOf("java"));
System.out.println(content.indexOf("java",4));//从角标为4的地方开始找
System.out.println(content.lastIndexOf("java"));
System.out.println("=====================================");
//字符串方法的使用
//7. public String trim() : 去掉字符串前后的空格
//8. public String toUpperCase() : 将小写转成大写 toLowerCase() 把大写转成小写
//9. public boolean endWith(String str) : 判断字符串是否以str结尾 startWith(String str) 判断是否以str开头
String content2 = " hello world ";
System.out.println(content2.trim());
System.out.println(content2.toUpperCase());
System.out.println(content2.toLowerCase());
String filename = "hello.java";
System.out.println(filename.endsWith(".java"));
System.out.println(filename.startsWith("hello"));
System.out.println("=====================================");
//字符串方法的使用
//10. public String replace(char oldChar,char newChar) : 将旧字符串替换成新字符串
//11. public String[] split(String str) : 根据str做拆分
System.out.println(content.replace("java","php"));
String say = "java is the best programing language,java xiang";
String[] arr = say.split("[ ,]+");//中括号里有空格和逗号意思是同时按照这两个来拆分,+ 号表示空格或者逗号可以连续有好几个
// System.out.println(arr.length);
for (String string : arr){
System.out.println(string);
}
System.out.println("=====================================");
//补充方法: equals、compareTo 用来比较大小
String s1 = "hello";
String s2 = "HELLO";
System.out.println(s1.equals(s2));//区分大小写比较
System.out.println(s1.equalsIgnoreCase(s2));//不区别大小写比较
String s3 = "abc"; //97
String s4 = "xyz"; //120
System.out.println(s3.compareTo(s4)); // s3 - s4 的值 即 97-120 = -23 如果第一位相等 比第二位
String s5 = "abc";
String s6 = "abcxyz";
System.out.println(s5.compareTo(s6)); //不一样长的时候 比长度 3 - 6 = -3
}
}


3. 案例演示
需求:
- 已知 String str = “this is a text”;
- 将str中的单词单独获取出来
- 将str中的text替换为practice
- 在text前面插入一个easy
- 将每个单词的首字母改为大写
package xyz.qianfeng.baozhuang.demo01;
public class example {
public static void main(String[] args) {
String str = "this is a text";
//将str中的单词单独获取出来
System.out.println("1. 将str中的单词单独获取出来:");
String[] arr = str.split(" ");
for (String s : arr){
System.out.println(s);
}
//将str中的text替换为practice
System.out.println("2. 将str中的text替换为practice:");
String str2 = str.replace("text","practice");
System.out.println(str2);
//在text前面插入一个easy
System.out.println("3. 在text前面插入一个easy:");
String str3 = str.replace("text","easy text");
System.out.println(str3);
//将每个单词的首字母改为大写
System.out.println("4. 将每个单词的首字母改为大写:");
String str4 = "";
for (int i = 0;i< arr.length;i++){
char first = arr[i].charAt(0);
// 把第一个字符转成大写
char upperFirst = Character.toUpperCase(first);
String newStr = upperFirst + arr[i].substring(1);//subString(index) 将一个字符串从第index出截取,只取后面的
// System.out.println(newStr);
str4 = str4 + newStr + " ";
}
System.out.println(str4);
}
}

4. 可变字符串
由于String的不可变性,会产生大量垃圾,所以产生了String增强类,即开辟缓冲区,直接在缓冲区操作,提高字符串效率,也节省内存。
StringBuffer:可变长字符串,JDK1.0提供,运行效率慢、线程安全。
StringBuilder:可变长字符串,JDK5.0提供,运行效率快、线程不安全。
和String的区别:
- 比String的效率高
- 比String节省内存
补充:
- 下标原则:含头不含尾
package xyz.qianfeng.string;
/**
* StringBuffer 和 StringBuilder
*
*/
public class demo07 {
public static void main(String[] args) {
//StringBuilder 跟 StringBuffer 使用方法一模一样
// StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
//1. append();追加
sb.append("java世界第一");
System.out.println(sb.toString());//StringBuffer的toString可以变为字符串
sb.append("java真香");
System.out.println(sb.toString());
sb.append("java不错");
System.out.println(sb.toString());
//2. insert();添加
sb.insert(0,"我在最前面");//添加到下标为0处
System.out.println(sb.toString());
//3. replace();替换 按照开始和结束的下标 下标原则:含头不含尾!
sb.replace(0,5,"hello");//替换0,1,2,3,4
System.out.println(sb.toString());
//4. delete(); 删除
sb.delete(0,5);
System.out.println(sb.toString());
//5. reverse();翻转
sb.reverse();
System.out.println(sb.toString());
//6. delete(0,sb.length) 清空StringBuffer
sb.delete(0,sb.length());
System.out.println(sb.toString());
}
}

验证 StringBuilder 的效率高于 StringBuffer:
package xyz.qianfeng.string;
public class Demo08 {
public static void main(String[] args) {
// 开始时间
long start = System.currentTimeMillis();
// String string = ""; //用时27664毫秒 27秒
// for (int i = 0; i < 99999; i++) {
// string += i;
// }
// System.out.println(string);
StringBuilder sb = new StringBuilder();//用时42毫秒 0.042秒
for (int i = 0; i < 99999; i++) {
sb.append(i);
}
System.out.println(sb.toString());
long end = System.currentTimeMillis();
System.out.println("用时:"+(end-start));
}
}
5.BigDecimal
思考:以下程序输出结果是多少?


double 和 float 存的是近似值 经过各种算数运算之后会出现误差,特殊场景下不允许出现误差 ,因此需要借助BigDecimal,它是一种精确存储。
位置:java.math包中。
作用:精确计算浮点数。
创建方式:BigDecimal bd = new BigDecimal(“1.0”);
方法:
-
加法:
BigDecimal add(BigDecimal bd)
-
减法:
BigDecimal subtract(BigDecimal bd)
-
乘法:
BigDecimal multiply(BigDecimal bd)
-
除法:
BigDecimal divide(BigDecimal bd)
结果除不尽的话 会报异常
所以除法用其他的构造方法:
divide(BigDecimal bd,int scal,RoundingMode mode)
- 参数scal:指定精确到小数点后几位。
- 参数mode:指定小数部分的取舍模式,通常为四舍五入(BigDecimal.ROUND_HALF_UP)
package xyz.qianfeng.string;
import xyz.oop.demo05.B;
import java.math.BigDecimal;
public class Demo09 {
public static void main(String[] args) {
//double 和 float 存的是近似值 经过各种算数运算之后会出现误差,特殊场景下不允许出现误差
double d1 = 1.0;
double d2 = 0.9;
// System.out.println(d1-d2);
//面试题
double result = (1.4-0.5)/0.9;
// System.out.println(result);
//BigDecimal,大的浮点数的精确计算
BigDecimal bigDecimal1 = new BigDecimal("1.0");//这里的构造方法一定要用字符串,因为字符串是最准确的
BigDecimal bigDecimal2 = new BigDecimal("0.9");
//减法
BigDecimal bigDecimal3 = bigDecimal1.subtract(bigDecimal2);
System.out.println(bigDecimal3);
//减法
BigDecimal bigDecimal4 = bigDecimal1.add(bigDecimal2);
System.out.println(bigDecimal4);
//乘法
BigDecimal bigDecimal5 = bigDecimal1.multiply(bigDecimal2);
System.out.println(bigDecimal5);
//除法
BigDecimal bigDecimal6 = new BigDecimal("1.4")
.subtract(new BigDecimal("0.5"))
.divide(new BigDecimal("0.9"));
System.out.println(bigDecimal6);
//结果除不尽的话 会报异常
BigDecimal bigDecimal7 = new BigDecimal("10")
.divide(new BigDecimal("3"),2,BigDecimal.ROUND_HALF_UP);
// 2的意思是保留两位小数
// BigDecimal.ROUND_HALF_UP的意思是四舍五入
System.out.println(bigDecimal7);
}
}
五、Date类
Date表示特定的瞬间,精确到毫秒。Date类中的大部分方法都已经被Calendar类中的方法所取代。
时间单位:
- 1秒 = 1000毫秒
- 1毫秒 = 1000微妙
- 1微秒 = 1000纳秒(毫微秒)

1970年是Unix操作系统元年。

很多都已经过时被替代了。


package xyz.qianfeng.date;
import java.util.Date;
public class demo01 {
public static void main(String[] args) {
//1. 创建Date对象
//今天 此时此刻
Date date1 = new Date();
System.out.println(date1.toString());
System.out.println(date1.toLocaleString());//虽然过时,但还可以使用
//昨天此时此刻
Date date2 = new Date(date1.getTime()-60*60*24*1000);
System.out.println(date2.toLocaleString());
//2. 方法 after before
boolean b1 = date1.after(date2);//判断今天是在昨天之后嘛
System.out.println(b1);
boolean b2 = date1.before(date2);//判断今天是在昨天之前嘛
System.out.println(b2);
//比较 comepareTo();
int d = date1.compareTo(date2);//正数则前大于后 负数则后大于前 0 则相等
System.out.println(d);
//比较是否相等 equals()
boolean b3 = date1.equals(date2);
System.out.println(b3);
}
}

六、Calendar类
Calendar提供了获取或设置各种日历字段的方法。
构造方法:
- protected Calendar() : 由于修饰符是protected,所以无法直接创建该对象。
其他方法:

package xyz.qianfeng.calendar;
import java.util.Calendar;
public class Demo01 {
public static void main(String[] args) {
//1. 创建Calendar对象(受保护的)
Calendar calendar = Calendar.getInstance();
// System.out.println(calendar.toString());//不常用
System.out.println(calendar.getTime().toLocaleString());//当前时间
System.out.println(calendar.getTimeInMillis());//1970年到现在的毫秒值
//2. 获取时间信息
//获取年
int year = calendar.get(Calendar.YEAR); //Calendar.YEAR == Calendar.1
//获取月 从0-11
int month = calendar.get(Calendar.MONTH);
//获取日
int day = calendar.get(Calendar.DAY_OF_MONTH); //Calendar.Date
//获取小时
int hour = calendar.get(Calendar.HOUR_OF_DAY);//HOUR 12 小时 ;HOUR_OF_DAY 24小时
//获取分钟
int minute = calendar.get(Calendar.MINUTE);
//获取秒
int second = calendar.get(Calendar.SECOND);
System.out.println(year+"年"+(month+1)+"月" + day + "日"+ hour + ":" + minute + ":" + second);
//修改时间
Calendar calendar2 = Calendar.getInstance();
calendar2.set(Calendar.DAY_OF_MONTH,5);
System.out.println(calendar2.getTime().toLocaleString());
//add方法修改时间
calendar2.add(Calendar.HOUR,1);//加一个小时
System.out.println(calendar2.getTime().toLocaleString());
calendar2.add(Calendar.HOUR,-1);//减一个小时
System.out.println(calendar2.getTime().toLocaleString());
//补充方法
int max = calendar2.getActualMaximum(Calendar.DAY_OF_MONTH);//当前这一月的最大一天
int min = calendar2.getActualMinimum(Calendar.DAY_OF_MONTH);//当前这一月的最小一天
System.out.println(max);
System.out.println(min);
}
}

七、SimpleDateFormat类
SimpleDateFormat是一个以与语言环境有关的方式格式化和解析日期的具体类。
进行格式化(日期 -> 文本)、解析(文本 -> 日期)。
常用的时间模式字母:

HH:24小时制 hh:12小时制
MM:月份 mm:分钟
package xyz.qianfeng.calendar;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class demo03 {
public static void main(String[] args) throws ParseException {
//1. 创建SimpleDateFormat对象 y:年 M:月
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
//2. 创建Date
Date date = new Date();
//3. 格式化date(把日期转换为字符串)
String str = sdf.format(date);
System.out.println(str);
//4. 解析(把字符串转换成日期)
Date date2 = sdf.parse("1990/05/01");
System.out.println(date2);
}
}

八、System类
System系统类,主要用于获取系统的属性数据和其他操作,构造方法私有的。里面的方法都是静态的,直接 System. 就可以使用。

package xyz.qianfeng.system;
import java.util.Arrays;
public class demo01 {
public static void main(String[] args) {
//arraycopy:实现数组的复制
//src:源数组 srcPOS:从哪个位置开始复制
//dest:目标数组
//destPos:目标数组的位置
//length:复制的长度
int[] arr = {11,12,1,34,45,48,90};
int[] dest = new int[8];
System.arraycopy(arr,0,dest,0,arr.length);
for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]);
}
// Arrays.copyOf() //其实这个方法也是使用的System.arraycopy
// System.currentTimeMillis(); 获取当前系统时间
long start = System.currentTimeMillis();
// for (int i = 0; i < 999; i++) {
// for (int j = 0; j < 999; j++) {
// int result = i + j;
// System.out.println(result);
// }
// }
long end = System.currentTimeMillis();
System.out.println("花费时间:"+ (end-start)/1000+ "秒");
//System.gc(); 告诉垃圾回收器回收垃圾
new Student("aaa",19);
new Student("aaa",19);
new Student("aaa",19);
System.gc();//告诉垃圾回收
//退出JVM
System.exit(0);//后面的代码不会再执行了
System.out.println("程序结束了....");
}
}
package xyz.qianfeng.system;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
protected void finalize() throws Throwable {
System.out.println("垃圾要回收了");
}
}
九、总结
- 内部类:
- 在一个类的内部再定义一个完整的类。
- 成员内部类、静态内部类、局部内部类、匿名内部类。
- Object 类:
- 所有类的直接或间接父类,可存储任何对象。
- 包装类:
- 基本数据类型所对应的引用数据类型,可以使Object统一所有的数据。
- String类:
- 字符串是常量,创建之后不可改变,字面值保存在字符串池中,可以共享。
- BigDecimal:
- 可精确计算浮点数。
- Date:
- 特定时间
- Calendar:
- 日历
- SimpleDateFormat:
- 格式化时间
- System:
- 系统类

浙公网安备 33010602011771号