10:内部类与常用类 || 别人所写好的正是我们要学习的

内部类与常用类


一、内部类

1. 内部类的分类

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

2. 什么是内部类

概念:在一个类的内部再定义一个完整的类

class Outer{
    class Inner{
        
    }
}
package xyz.qianfeng.innerClass;
//身体
public class Body {
    //头部  内部类也会生成class文件 Body$Header.class
    class Header{

    }
}

image-20220109135513044

特点:

  1. 编译之后可生成独立的字节码文件。
  2. 内部类可直接访问外部类的私有成员,而不破坏封装。
  3. 内部类可以为外部类提供必要的内部功能组件。

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

image-20220109141314027

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类型可以存储任何对象。

  • 作为参数,可接受任何对象。
  • 作为返回值,可返回任何对象。

image-20220109155433919

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相同,指向的是同一个对象
    }

}

image-20220109161444355

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

    }

}

image-20220109162026272

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

image-20220109162106938

但其实经过计算器计算发现这两个值是一样的,只不过前者为16进制 后者为10进制。

计算器打开快捷键:Win+R 输入:calc

image-20220109161941062

但有些时候 我们并不想看到原始的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

image-20220109162953752

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() 方法覆盖步骤:

  1. 比较两个引用是否指向同一个对象
  2. 判断obj是否为null
  3. 判断两个引用指向的实际对象类型是否一致
  4. 强制类型转换
  5. 依次比较各个属性值是否相同
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

    }

}

image-20220109170233703

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("回收垃圾");
    }
    
}

image-20220109171315800


三、包装类

1. 什么是包装类

基本数据类型所对应的引用数据类型。

八种四类的基本数据类型,这八种基本数据类型并没有什么可以直接使用的方法,除了用运算符做一些操作。而且基本数据类型是存放在栈中的,有了包装类之后,将存放在堆中,在栈中引用。

为了能对基本数据类型进行一些方法上的操作,sun公司做了这些基本数据类型对应的引用数据类型,叫做基本数据类型的包装类。

Object可统一所有数据,包装类的默认值是null;(引用类型的默认值都为null)

这八个基本数据类型对应的引用类型如下:

基本数据类型 包装类型
byte Byte
short Short
int Integer
long Long
float Float
double Doule
boolean Boolean
char Characte
  1. Byte:

image-20220109172727712

  1. Character

image-20220109172806208

  1. Double

image-20220109172822510

  1. Integer

image-20220109172841052

  1. Long

image-20220109172905033

  1. Float

image-20220109172919533

  1. Short

image-20220109173009711

  1. Boolean

image-20220109173046602

2. 类型转换与装箱、拆箱

装箱:将基本类型转换为引用类型的过程。

拆箱:将引用类型转换为基本类型的过程。

8种包装类提供不同类型间的转换方式:

  • Number父类中提供的6个共性方法。这六个方法可以用来拆箱,将引用类型转换为基本类型。

    image-20220109173621413

    image-20220109173640070

  • 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代码:

image-20220109175705862

对比发现:自动装箱和拆箱的背后是编译器自动使用了手动装箱拆箱的方法。

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

image-20220109181426769

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 打开画图工具。

字符串赋值方法:

  1. String s = "Hello";//产生一个对象,字符串池中存储。
  2. 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


    }
}

image-20220109190952812

2. 常用方法

  1. public int length() : 返回字符串的长度
  2. public char charAt(int index) : 根据下标获取字符
  3. public boolean contains(String str) : 判断当前字符串中是否包含str
  4. public char[] toCharArray() : 将字符串转换成数组
  5. public int indexOf(String str) : 查找str首次出现的下标,存在,则返回该下标;不存在,则返回-1
  6. public int lastIndexOf(String str) : 查找字符串在当前字符串中最后一次出现的下标索引。
  7. public String trim() : 去掉字符串前后的空格
  8. public String toUpperCase() : 将小写转成大写
  9. public boolean endWith(String str) : 判断字符串是否以str结尾
  10. public String replace(char oldChar,char newChar) : 将旧字符串替换成新字符串
  11. public String[] split(String str) : 根据str做拆分
  12. 补充方法:
    • 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
     }
}

image-20220109201608747

image-20220109201701319

3. 案例演示

需求:

  • 已知 String str = “this is a text”;
  1. 将str中的单词单独获取出来
  2. 将str中的text替换为practice
  3. 在text前面插入一个easy
  4. 将每个单词的首字母改为大写
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);
    }

}

image-20220109203807454

4. 可变字符串

由于String的不可变性,会产生大量垃圾,所以产生了String增强类,即开辟缓冲区,直接在缓冲区操作,提高字符串效率,也节省内存。

StringBuffer:可变长字符串,JDK1.0提供,运行效率慢、线程安全。

StringBuilder:可变长字符串,JDK5.0提供,运行效率快、线程不安全。

和String的区别:

  1. 比String的效率高
  2. 比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());
    }
}

image-20220109205426488

验证 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

思考:以下程序输出结果是多少?

image-20220109210306225

image-20220109210723773

double 和 float 存的是近似值 经过各种算数运算之后会出现误差,特殊场景下不允许出现误差 ,因此需要借助BigDecimal,它是一种精确存储。

位置:java.math包中。

作用:精确计算浮点数。

创建方式:BigDecimal bd = new BigDecimal(“1.0”);

方法:

  1. 加法:

    BigDecimal add(BigDecimal bd)

  2. 减法:

    BigDecimal subtract(BigDecimal bd)

  3. 乘法:

    BigDecimal multiply(BigDecimal bd)

  4. 除法:

    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纳秒(毫微秒)

image-20220109212809119

1970年是Unix操作系统元年。

image-20220109212904264

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

image-20220109212946216

image-20220109213000784

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


    }
}

image-20220109213817330


六、Calendar类

Calendar提供了获取或设置各种日历字段的方法。

构造方法:

  • protected Calendar() : 由于修饰符是protected,所以无法直接创建该对象。

其他方法:

image-20220109214024196

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

    }
}

image-20220109215928393


七、SimpleDateFormat类

SimpleDateFormat是一个以与语言环境有关的方式格式化和解析日期的具体类。

进行格式化(日期 -> 文本)、解析(文本 -> 日期)。

常用的时间模式字母:

image-20220109220217967

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


    }
}

image-20220109221101041


八、System类

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

image-20220109221331913

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:
    • 系统类
posted @ 2022-01-09 22:52  Laxsilence  阅读(68)  评论(1)    收藏  举报