Java内部类与常用类

1、内部类

在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。

内部类可以很好地实现隐藏,一般的非内部类是不允许有 private 与 protected 权限的,但内部类可以。内部类拥有外部类的所有元素的访问权限。

内部类的特点如下:

  1. 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
  2. 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
  3. 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。

有关内部类的说明有如下几点。

  • 外部类只有两种访问级别:public 和默认;内部类则有 4 种访问级别:public、protected、 private 和默认。
  • 在外部类中可以直接通过内部类的类名访问内部类。
InnerClass ic = new InnerClass();    // InnerClass为内部类的类名
  • 在外部类以外的其他类中则需要通过内部类的完整类名访问内部类。
Test.InnerClass ti = new Test().new InnerClass();    // Test.innerClass是内部类的完整类名
  • 内部类与外部类不能重名。

提示:内部类的很多访问规则可以参考变量和方法。另外使用内部类可以使程序结构变得紧凑,但是却在一定程度上破坏了 Java面向对象的思想。

1.1、成员内部类

也叫实例内部类,是指没有用 static 修饰的内部类,有的地方也称为非静态内部类。示例代码如下:

public class Outer {
    class Inner {
        // 成员内部类
    }
}

上述示例中的 Inner 类就是成员内部类。成员内部类有如下特点。

1)在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例。

public class Outer {
    class Inner1 {
    }
    Inner1 i = new Inner1(); // 不需要创建外部类实例
    public void method1() {
        Inner1 i = new Inner1(); // 不需要创建外部类实例
    }
    public static void method2() {
        Inner1 i = new Outer().new inner1(); // 需要创建外部类实例
    }
    class Inner2 {
        Inner1 i = new Inner1(); // 不需要创建外部类实例
    }
}
class OtherClass {
    Outer.Inner i = new Outer().new Inner(); // 需要创建外部类实例
}

2)在成员内部类中,可以访问外部类的所有成员。

public class Outer {
    public int a = 100;
    static int b = 100;
    final int c = 100;
    private int d = 100;
    public String method1() {
        return "实例方法1";
    }
    public static String method2() {
        return "静态方法2";
    }
    class Inner {
        int a2 = a + 1; // 访问public的a
        int b2 = b + 1; // 访问static的b
        int c2 = c + 1; // 访问final的c
        int d2 = d + 1; // 访问private的d
        String str1 = method1(); // 访问实例方法method1
        String str2 = method2(); // 访问静态方法method2
    }
    public static void main(String[] args) {
        Inner i = new Outer().new Inner(); // 创建内部类实例
        System.out.println(i.a2); // 输出101
        System.out.println(i.b2); // 输出101
        System.out.println(i.c2); // 输出101
        System.out.println(i.d2); // 输出101
        System.out.println(i.str1); // 输出实例方法1
        System.out.println(i.str2); // 输出静态方法2
    }
}

提示:如果有多层嵌套,则内部类可以访问所有外部类的成员。

3)在外部类中不能直接访问内部类的成员,而必须通过内部类的实例去访问。如果类 A 包含内部类 B,类 B 中包含内部类 C,则在类 A 中不能直接访问类 C,而应该通过类 B 的实例去访问类 C。

4)外部类实例与内部类实例是一对多的关系,也就是说一个内部类实例只对应一个外部类实例,而一个外部类实例则可以对应多个内部类实例。

如果成员内部类 B 与外部类 A 包含有同名的成员 t,则在类 B 中 t 和 this.t 都表示 B 中的成员 t,而 A.this.t 表示 A 中的成员 t。

public class Outer {
    int a = 10;
    class Inner {
        int a = 20;
        int b1 = a;
        int b2 = this.a;
        int b3 = Outer.this.a;
    }
    public static void main(String[] args) {
        Inner i = new Outer().new Inner();
        System.out.println(i.b1); // 输出20
        System.out.println(i.b2); // 输出20
        System.out.println(i.b3); // 输出10
    }
}

5)在成员内部类中不能定义 static 成员,除非同时使用final 和 static 修饰。

1.2、静态内部类

静态内部类是指使用 static 修饰的内部类。示例代码如下:

public class Outer {
    static class Inner {
        // 静态内部类
    }
}

上述示例中的 Inner 类就是静态内部类。静态内部类有如下特点。

1)在创建静态内部类的实例时,不需要创建外部类的实例。

public class Outer {
    static class Inner {
    }
}
class OtherClass {
    Outer.Inner oi = new Outer.Inner();
}

2)静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例。

public class Outer {
    static class Inner {
        int a = 0;    // 实例变量a
        static int b = 0;    // 静态变量 b
    }
}
class OtherClass {
    Outer.Inner oi = new Outer.Inner();
    int a2 = oi.a;    // 访问实例成员
    int b2 = Outer.Inner.b;    // 访问静态成员
}

3)静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。

public class Outer {
    int a = 0;    // 实例变量
    static int b = 0;    // 静态变量
    static class Inner {
        Outer o = new Outer;
        int a2 = o.a;    // 访问实例变量
        int b2 = b;    // 访问静态变量
    }
}

1.3、局部内部类

局部内部类是指在一个方法中定义的内部类。示例代码如下:

public class Test {
    public void method() {
        class Inner {
            // 局部内部类
        }
    }
}

局部内部类有如下特点:

1)局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。

2)局部内部类只在当前方法中有效。

public class Test {
    Inner i = new Inner();    // 编译出错
    Test.Inner ti = new Test.Inner();    // 编译出错
    Test.Inner ti2 = new Test().new Inner();    // 编译出错
    public void method() {
        class Inner{
        
        }
        Inner i = new Inner();
    }
}

3)局部内部类中不能定义 static 成员。

4)局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。

5)在局部内部类中可以访问外部类的所有成员。

6)在局部内部类中只可以访问当前方法中 final 类型的参数与变量(jdk1.8以后可以调用非final类型,但调用过后会自动给该变量自动加上final,不可再修改)。如果方法中的成员与外部类中的成员同名,则可以使用 .this. 的形式访问外部类中的成员。

public class Test {
    int a = 0;
    int d = 0;
    public void method() {
        int b = 0;
        final int c = 0;
        final int d = 10;
        class Inner {
            int a2 = a;    // 访问外部类中的成员
            // int b2 = b;    // 编译出错
            int c2 = c;    // 访问方法中的成员
            int d2 = d;    // 访问方法中的成员
            int d3 = Test.this.d;    //访问外部类中的成员
        }
        Inner i = new Inner();
        System.out.println(i.d2);    // 输出10
        System.out.println(i.d3);    // 输出0
    }
    public static void main(String[] args) {
        Test t = new Test();
        t.method();
    }
}

1.4、匿名内部类

匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下:

new <类或接口>() {
    // 类的主体
};

这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。使用匿名类可使代码更加简洁、紧凑,模块化程度更高。

匿名类有两种实现方式:

  • 继承一个类,重写其方法。
  • 实现一个接口(可以是多个),实现其方法。

下面通过代码来说明。

public class Out {
    void show() {
        System.out.println("调用 Out 类的 show() 方法");
    }
}
public class TestAnonymousInterClass {
    // 在这个方法中构造一个匿名内部类
    private void show() {
        Out anonyInter = new Out() {//此次也可以实现接口或者抽象类
            // 获取匿名内部类的实例
            void show() {
                System.out.println("调用匿名类中的 show() 方法");
            }
        };
        anonyInter.show();
    }
    public static void main(String[] args) {
        TestAnonymousInterClass test = new TestAnonymousInterClass();
        test.show();
    }
}

程序的输出结果如下:

调用匿名类中的 show() 方法

从输出结果可以看出,匿名内部类有自己的实现。

提示:匿名内部类实现一个接口的方式与实现一个类的方式相同,这里不再赘述。

匿名类有如下特点:

1)匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中final类型的局部变量和参数。

public static void main(String[] args) {
    int a = 10;
    final int b = 10;
    Out anonyInter = new Out() {
        void show() {
            // System.out.println("调用了匿名类的 show() 方法"+a);    // 编译出错
            System.out.println("调用了匿名类的 show() 方法"+b);    // 编译通过
        }
    };
    anonyInter.show();
}

从 Java 8 开始添加了 Effectively final 功能,在 Java 8 及以后的版本中代码第 6 行不会出现编译错误。

也就是说从 Java 8 开始,它不要求程序员必须将访问的局部变量显式的声明为 final 的。只要该变量不被重新赋值就可以。

一个非 final 的局部变量或方法参数,其值在初始化后就从未更改,那么该变量就是 effectively final。

2)匿名类中允许使用非静态代码块进行成员初始化操作。

Out anonyInter = new Out() {
    int i; {    // 非静态代码块
        i = 10;    //成员初始化
    }
    public void show() {
        System.out.println("调用了匿名类的 show() 方法"+i);
    }
};

3)匿名类的非静态代码块会在父类的构造方法之后被执行。

2、Object 类

  • 超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
  • 任何类,如没有书写 extends 显示继承某个类,都默认直接继承 Object 类,否则为间接继承。
  • Object 类中所定义的方法,是所有对象都具备的方法。
  • Object 类型可以存储任何对象。
    • 作为参数,可接受任何对象。
    • 作为返回值,可返回任何对象。

2.1、getClass() 方法

  • public final Class<?> getClass() {}
  • 返回引用中存储的实际对象类型。
  • 应用:通常用于判断两个引用中实际存储对象类型是否一致。
package com.liuxiang.Object;

public class ObjectDemo {
    public static void main(String[] args) {
        Student s1 = new Student("刘德华",18);
        Student s2 = new Student("梁朝伟",19);
        //getClass方法
        //判断s1和s2是不是同一个类型
        Class c1 = s1.getClass();
        Class c2 = s2.getClass();
        System.out.println("---------------1getClass--------------------");
        System.out.println(c1==c2? "是同一个类型" : "不是同一个类型");
    }
}

package com.liuxiang.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;
    }
}
---------------1getClass--------------------
是同一个类型

2.2、hashCode()方法

  • public int hashCode() {}
  • 返回该对象的哈希码值。
  • 哈希值根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值。
  • 一般情况下相同对象返回相同哈希码。

重写hashCode()方法

@Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
package com.liuxiang.Object;

public class ObjectDemo {
    public static void main(String[] args) {
        Student s1 = new Student("刘德华",18);
        Student s2 = new Student("梁朝伟",19);
        
        //hashCode方法
        System.out.println("---------------2hashCode--------------------");
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(new Student("刘德华",18).hashCode());//重写hashCode方法后返回一样的hashCode值
        Student s3 = s1;
        System.out.println(s3.hashCode());
    }
}

---------------2hashCode--------------------
650297124
822995025
650297124
650297124

2.3、toString()方法

  • public String toString() {}
  • 返回该对象的字符串表示(表现形式)。
  • 可以根据程序需求覆盖该方法,如:展示对象各个属性值。

查看源码如下:

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

@符号后面的数字就是哈希码的十六进制

重写toString()方法

  @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
package com.liuxiang.Object;

public class ObjectDemo {
    public static void main(String[] args) {
        Student s1 = new Student("刘德华",18);
        Student s2 = new Student("梁朝伟",19);
        
        //toString方法
        System.out.println("----------------3toString-------------------");
        System.out.println(s1.toString());
        System.out.println(s2.toString());
    }
}

----------------3toString-------------------
Student{name='刘德华', age=18}
Student{name='梁朝伟', age=19}

2.4、equals()方法

  • public boolean equals (Object obj) {}
  • 默认实现为(this == obj),比较两个对象地址是否相同。
  • 可进行覆盖,比较两个对象的内容是否相同。

equals() 方法覆盖步骤**

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

重写equals()方法

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }
package com.liuxiang.Object;

public class ObjectDemo {
    public static void main(String[] args) {
        Student s1 = new Student("刘德华",18);
        Student s2 = new Student("梁朝伟",19);

        //equals方法
        System.out.println("----------------4equals-------------------");
        System.out.println(s1.equals(s2));
        System.out.println(s1.equals(new Student("刘德华",18)));
    }
}

----------------4equals-------------------
false
true

2.5、finalize()方法

  • 当对象被判定为垃圾对象时,由 JVM 自动调用此方法,用以标记垃圾对象,进入回收队列。
  • 垃圾对象:没有有效引用指向此对象时,为垃圾对象。
  • 垃圾回收:由 GC 销毁垃圾对象,释放数据存储空间。
  • 自动回收机制:JVM 的内存耗尽,一次性回收所有垃圾对象。
  • 手动回收机制:使用 System. gc(); 通知 JVM 执行垃圾回收。

重写finalize()方法

@Override
    protected void finalize() throws Throwable {
        System.out.println(this.name+"对象被回收了");
        //super.finalize();
    }
package com.liuxiang.Object;

public class ObjectDemo {
    public static void main(String[] args) {
        Student s1 = new Student("刘德华",18);
        Student s2 = new Student("梁朝伟",19);

        //finalize()方法
        System.out.println("----------------5finalize-------------------");
        System.gc();//不是垃圾对象不回收
        new Student("刘德华",18);
        new Student("梁朝伟",19);
        System.gc();//回收前面两个垃圾对象
    }
}

----------------5finalize-------------------
梁朝伟对象被回收了
刘德华对象被回收了

3、包装类

  • 基本数据类型所对应的引用数据类型。
  • Object 可统一所有数据,包装类的默认值是null。

3.1、类型转换与装箱、拆箱

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

  • Number父类(含有子类Byte,Double,Float,Integer,Long,Short等等)中提供的6个共性方法。

  • parseXXX()静态方法,实现字符串与基本类型之间的转换。

  • valueof()静态方法,基本数据类型转引用类型。

package com.liuxiang.Packaging;

public class BoxingDemo {
    public static void main(String[] args) {
        //类型转换:装箱,基本类型转成引用类型的过程
        int num = 18;
        Integer integer1 = new Integer(num);
        Integer integer2 = Integer.valueOf(num);//静态方法,直接通过类.方法名调用,不需要实例化对象
        System.out.println("装箱:"+integer1);

        //类型转换:拆箱,引用类型转成基本类型的过程
        Integer integer3 = new Integer(100);
        int num1 = integer3.intValue();
        System.out.println("拆箱:"+num1);

        //以上是JDK1.5之前用法,JDK1.5之后,提供了自动装箱和拆箱
        int age = 28;
        //自动装箱
        Integer integer4 = age;
        System.out.println("自动装箱:"+integer4);
        //自动拆箱
        int age2 = integer4;
        System.out.println("自动拆箱:"+age2);
    }
}
package com.liuxiang.Packaging;

public class BasicAndString {
    public static void main(String[] args) {
        //1.基本类型转成字符串
        int n1 = 15;
        //1.1使用+号
        String s1 = n1+"";
        //1.2使用Integer中的toString()方法
        String s2 = Integer.toString(n1);
        String s3 = Integer.toString(n1,16);//转换为16进制
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);

        //2.字符串转成基本类型
        String str = "1220";//不能是非数字字符串
        int n2 = Integer.parseInt(str);
        System.out.println(n2);

        //boolean字符串形式转成基本类型:"true"--->true   非"true"--->false
        String str2 = "true";
        String str3 = "true1";
        boolean b = Boolean.parseBoolean(str2);
        boolean b1 = Boolean.parseBoolean(str3);
        System.out.println(b);
        System.out.println(b1);
    }
}

3.2、整数缓冲区

  • Java预先创建了256个常用的整数包装类型对象。
  • 在实际应用当中,对已创建的对象进行复用。

Java中自动装箱其实调用的是valueof方法,查看valueof方法源码可以发现,该方法会对 -128~127之间的整数进行固定使用cache数组中已经在类加载时new出来的引用地址,这些地址已经指向了这256个常用的整数,在Java中因为这256个整数属于在编码中使用频率极高的整数,因此被称作是常用整数。源码如下:

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

 private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

编写示例代码如下:

package com.liuxiang.Packaging;

public class IntegerBuffer  {
    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;
        //自动装箱,其实调用的是valueof方法,即Integer integer3 = Integer.valueOf(100);
        //因为100介于-128到127之间,所以直接从缓冲区中取值,并没有实例化对象,因此为true
        Integer integer4 = 100;
        System.out.println(integer3==integer4);;

        Integer integer5 = 200;
        //自动装箱,其实调用的是valueof方法,即Integer integer5 = Integer.valueOf(100);
        //因为200不介于-128到127之间,所以不能直接从缓冲区中取值,要实例化对象,因此为false
        Integer integer6 = 200;
        System.out.println(integer5==integer6);
    }


}
false
true
false

4、String类

  • 字符串是常量,创建之后不可改变。
  • 字符串字面值存储在字符串池中,可以共享。
  • String s = "Hello" ; //产生一个对象,字符串池中存储。
  • String s = new String(“Hello”); //产生两个对象,堆、字符串池各存储一个。
package com.liuxiang.String;

public class StringDemo {
    public static void main(String[] args) {
        String name = "hello";//"hello" 常量存储在字符串池中
        name = "zhangsan";//"zhangsan"赋值给name变量,给字符串赋值时,并没有修改数据,而是重新开辟一个空间
        String name2 = "zhangsan";

        //字符串的另一种创建方式,new String();
        String str = new String("Java是最好的编程语言");
        String str2 = new String("Java是最好的编程语言");
        System.out.println(str==str2);//比较地址 false
        System.out.println(str.equals(str2));//equals方法在String类中重写了,因此equals方法比较内容 true
    }
}
false
true

4.1、常用方法

  • public int length():返回字符串的长度。
  • public char charAt(int index):根据下标获取字符。
  • public boolean contains(String str):判断当前字符串中是否包含str。
package com.liuxiang.String;

public class StringMethodDemo {
    public static void main(String[] args) {
        String content = "Java是世界上最好的编程语言 ";
        
        //length();返回字符串的长度
        System.out.println(content.length());
        
        //charAt(int index);返回某个位置的字符
        System.out.println(content.charAt(6));
        
        //contains(String str);判断是否包含某个子字符串
        System.out.println(content.contains("Java"));
        
    }
}

16
界
true
  • public char[] toCharArray():将字符串转换成数组。
  • public int indexOf(String str):查找str首次出现的下标,存在,则返回该下标;不存在,则返回-1。
  • public int lastIndexOf(String str);查找字符串在当前字符串中最后一次出现的下标索引。
package com.liuxiang.String;

import java.util.Arrays;

public class StringMethodDemo {
    public static void main(String[] args) {
        String content = "Java是世界上最好的编程语言 ";

        //toCharArray();返回字符串对应的数组。
        System.out.println(Arrays.toString(content.toCharArray()));

        //indexOf();返回字符串首次出现的下标,存在,则返回该下标;不存在,则返回-1。
        System.out.println(content.indexOf("Java"));

        //lastIndexOf();返回字符串在当前字符串中最后一次出现的下标索引。
        System.out.println(content.lastIndexOf("语"));
    }
}
[J, a, v, a, 是, 世, 界, 上, 最, 好, 的, 编, 程, 语, 言,  ]
0
13
  • public String trim():去掉字符串前后的空格。
  • public String toUpperCase():将小写转成大写。
  • public String toLowerCase():将大写转成小写。
  • public boolean endWith(String str):判断字符串是否以str结尾。
  • public boolean startWith(String str):判断字符串是否以str开头。
package com.liuxiang.String;

import java.util.Arrays;
import java.util.Locale;

public class StringMethodDemo {
    public static void main(String[] args) {
        String content1 = "   Hello   World   ";

        //trim();去掉字符串前后的空格。
        System.out.println(content1.trim());

        //toUpperCase();将小写转成大写。
        System.out.println(content1.toUpperCase());

        //toLowerCase();将大写转成小写。
        System.out.println(content1.toLowerCase());

        String filename = "hello.java";
        //endWith(String str);判断字符串是否以str结尾。
        System.out.println(filename.endsWith(".java"));

        //startsWith(String str);判断字符串是否以str开头。
        System.out.println(filename.startsWith("hello"));
    }
}

Hello   World
   HELLO   WORLD   
   hello   world   
true
true
  • public String substring(int beginIndex, int endIndex):截取字符串beginIndex到endIndex的子字符串
  • public String replace(char oldChar, char newChar):将旧字符串替换成新字符串。
  • public String[] split(String str):根据str做拆分。
package com.liuxiang.String;

import java.util.Arrays;
import java.util.Locale;

public class StringMethodDemo {
    public static void main(String[] args) {
        String content2 = "Java是世界上最好的编程语言,Java真香";

        //substring(int beginIndex,int endIndex);截取字符串beginIndex到endIndex的子字符串
        String str = content2.substring(2,8);
        System.out.println(str);

        //replace(char oldChar, char newChar);将旧字符串替换成新字符串。
        String content3 = content2.replace("Java","php");
        System.out.println(content2);
        System.out.println(content3);

        String content4 = "Java is the best programing   language,java xiang";

        //split(String str);根据str做拆分。
        String[] content5 = content4.split("[ ,]+");
        System.out.println(content5.length);
        for (int i = 0; i < content5.length; i++) {
            System.out.println(content5[i]);
        }

        System.out.println("--------------补充-------------------");
        String s1 = "hello";
        String s2 = "HELLO";
        System.out.println(s1.equals(s2));
        System.out.println(s1.equalsIgnoreCase(s2));

        String s3 = "abc";//a的ASCII码97
        String s4 = "xyz";//x的ASCII码120
        System.out.println(s3.compareTo(s4));//比较首字母大小,97-120

        String s5 = "abc";//字符串长度3
        String s6 = "abcxyz";//字符串长度6
        System.out.println(s5.compareTo(s6));//比较字符串长度,3-6

    }
}

va是世界上
Java是世界上最好的编程语言,Java真香
php是世界上最好的编程语言,php真香
8
Java
is
the
best
programing
language
java
xiang
--------------补充-------------------
false
true
-23
-3

4.2、StringBuffer类

  • 可变长字符串,JDK1.0提供,运行效率慢、线程安全。
package com.liuxiang.String;

/**
 * 和String区别 (1)效率比String高 (2)比String节省内存
 * @author 86187
 */

public class StringBufferDemo {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();

        //1.append();追加
        sb.append("Java天下第一");
        System.out.println(sb.toString());
        sb.append(" Java真香");
        System.out.println(sb.toString());

        //2.insert();添加
        sb.insert(0,"我是第一个 ");
        System.out.println(sb.toString());

        //replace();替换
        sb.replace(0,2,"替换");
        System.out.println(sb.toString());

        //delete();删除
        sb.delete(0,2);
        System.out.println(sb.toString());

        //reverse();反转
        sb.reverse();
        System.out.println(sb.toString());

        //delete();清空
        sb.delete(0,sb.length());
        System.out.println(sb.toString());
    }
}
Java天下第一
Java天下第一 Java真香
我是第一个 Java天下第一 Java真香
替换第一个 Java天下第一 Java真香
第一个 Java天下第一 Java真香
香真avaJ 一第下天avaJ 个一第

4.3、StringBuilder类

  • 可变长字符串,JDK5.0提供,运行效率快、线程不安全。
package com.liuxiang.String;

/**
 * 和String区别 (1)效率比String高 (2)比String节省内存
 * @author 86187
 */

public class StringBuilderDemo {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();

        //1.append();追加
        sb.append("Java天下第一");
        System.out.println(sb.toString());
        sb.append(" Java真香");
        System.out.println(sb.toString());

        //2.insert();添加
        sb.insert(0,"我是第一个 ");
        System.out.println(sb.toString());

        //replace();替换
        sb.replace(0,2,"替换");
        System.out.println(sb.toString());

        //delete();删除
        sb.delete(0,2);
        System.out.println(sb.toString());

        //reverse();反转
        sb.reverse();
        System.out.println(sb.toString());

        //delete();清空
        sb.delete(0,sb.length());
        System.out.println(sb.toString());
    }
}
Java天下第一
Java天下第一 Java真香
我是第一个 Java天下第一 Java真香
替换第一个 Java天下第一 Java真香
第一个 Java天下第一 Java真香
香真avaJ 一第下天avaJ 个一第

4.4、验证效率

编写以下代码验证StringBuilder效率高于String

package com.liuxiang.String;

/**
 * 验证StringBuilder效率高于String
 * @author 86187
 */

public class effectivenessDemo {
    public static void main(String[] args) {
        //开始时间
        Long start = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < 99999; i++) {
            str +=i;
        }
        System.out.println(str);
        long end = System.currentTimeMillis();
        System.out.println("用时:"+(end-start));
    }
}
用时:17997
package com.liuxiang.String;

/**
 * 验证StringBuilder效率高于String
 * @author 86187
 */

public class effectivenessDemo {
    public static void main(String[] args) {
        //开始时间
        Long start = System.currentTimeMillis();
//        String str = "";
//        for (int i = 0; i < 99999; i++) {
//            str +=i;
//        }
//        System.out.println(str);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 99999; i++) {
            sb.append(i);
        }
        System.out.println(sb.toString());
        long end = System.currentTimeMillis();
        System.out.println("用时:"+(end-start));
    }
}
用时:29

5、Arrays工具类

Arrays 类是一个工具类,其中包含了数组操作的很多方法。这个 Arrays 类里均为 static 修饰的方法(static 修饰的方法可以直接通过类名调用),可以直接通过 Arrays.xxx(xxx) 的形式调用方法。常用方法如下:

  • int binarySearch(type[] a, type key)

使用二分法查询 key 元素值在 a 数组中出现的索引,如果 a 数组不包含 key 元素值,则返回负数。调用该方法时要求数组中元素己经按升序排列,这样才能得到正确结果。

  • int binarySearch(type[] a, int fromIndex, int toIndex, type key)

这个方法与前一个方法类似,但它只搜索 a 数组中 fromIndex 到 toIndex 索引的元素。调用该方法时要求数组中元素己经按升序排列,这样才能得到正确结果。

  • type[] copyOf(type[] original, int length)

这个方法将会把 original 数组复制成一个新数组,其中 length 是新数组的长度。如果 length 小于 original 数组的长度,则新数组就是原数组的前面 length 个元素,如果 length 大于 original 数组的长度,则新数组的前面元索就是原数组的所有元素,后面补充 0(数值类型)、false(布尔类型)或者 null(引用类型)。

  • type[] copyOfRange(type[] original, int from, int to)

这个方法与前面方法相似,但这个方法只复制 original 数组的 from 索引到 to 索引的元素。

  • boolean equals(type[] a, type[] a2)

如果 a 数组和 a2 数组的长度相等,而且 a 数组和 a2 数组的数组元素也一一相同,该方法将返回 true。

  • void fill(type[] a, type val)

该方法将会把 a 数组的所有元素都赋值为 val。

  • void fill(type[] a, int fromIndex, int toIndex, type val)

该方法与前一个方法的作用相同,区别只是该方法仅仅将 a 数组的 fromIndex 到 toIndex 索引的数组元素赋值为 val。

  • void sort(type[] a)

该方法对 a 数组的数组元素进行排序。

  • void sort(type[] a, int fromIndex, int toIndex)

该方法与前一个方法相似,区别是该方法仅仅对 fromIndex 到 toIndex 索引的元素进行排序。

  • String toString(type[] a)

该方法将一个数组转换成一个字符串。该方法按顺序把多个数组元素连缀在一起,多个数组元素使用英文逗号,和空格隔开。

下面程序示范了 Arrays 类的用法。

public class ArraysTest {
    public static void main(String[] args) {
        // 定义一个a数组
        int[] a = new int[] { 3, 4, 5, 6 };
        // 定义一个a2数组
        int[] a2 = new int[] { 3, 4, 5, 6 };
        // a数组和a2数组的长度相等,毎个元素依次相等,将输出true
        System.out.println("a数组和a2数组是否相等:" + Arrays.equals(a, a2));
        // 通过复制a数组,生成一个新的b数组
        int[] b = Arrays.copyOf(a, 6);
        System.out.println("a数组和b数组是否相等:" + Arrays.equals(a, b));
        // 输出b数组的元素,将输出[3, 4, 5, 6, 0, 0]
        System.out.println("b 数组的元素为:" + Arrays.toString(b));
        // 将b数组的第3个元素(包括)到第5个元素(不包括)賦值为1
        Arrays.fill(b, 2, 4, 1);
        // 输出b数组的元素,将输出[3, 4, 1, 1, 0, 0]
        System.out.println("b 数组的元素为:" + Arrays.toString(b));
        // 对b数组进行排序
        Arrays.sort(b);
        // 输出b数组的元素.将输出[0,0,1,1,3,4]
        System.out.println("b数组的元素为:" + Arrays.toString(b));
    }
}

6、Scanner用户交互类

java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入。

下面是创建 Scanner 对象的基本语法:

Scanner s = new Scanner(System.in);

接下来我们演示一个最简单的数据输入,并通过 Scanner 类的 next() 与 nextLine() 方法获取输入的字符串,在读取前我们一般需要 使用 hasNext 与 hasNextLine 判断是否还有输入的数据:

6.1、使用 next 方法:

import java.util.Scanner; 
 
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        // 从键盘接收数据
 
        // next方式接收字符串
        System.out.println("next方式接收:");
        // 判断是否还有输入
        if (scan.hasNext()) {
            String str1 = scan.next();
            System.out.println("输入的数据为:" + str1);
        }
        scan.close();
    }
}

执行以上程序输出结果为:

runoob com
输入的数据为:runoob

6.2、使用 nextLine 方法:

import java.util.Scanner;
 
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        // 从键盘接收数据
 
        // nextLine方式接收字符串
        System.out.println("nextLine方式接收:");
        // 判断是否还有输入
        if (scan.hasNextLine()) {
            String str2 = scan.nextLine();
            System.out.println("输入的数据为:" + str2);
        }
        scan.close();
    }
}

执行以上程序输出结果为:

runoob com
输入的数据为:runoob com

6.3、next() 与 nextLine() 区别

next():

  • 1、一定要读取到有效字符后才可以结束输入。
  • 2、对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
  • 3、只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
  • next() 不能得到带有空格的字符串。

nextLine():

  • 1、以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符。
  • 2、可以获得空白。

6.4、使用 nextDouble 方法

以下实例我们可以输入多个数字,并求其总和与平均数,每输入一个数字用回车确认,通过输入非数字来结束输入并输出执行结果:

import java.util.Scanner;
 
class RunoobTest {
    public static void main(String[] args) {
        System.out.println("请输入数字:");
        Scanner scan = new Scanner(System.in);
 
        double sum = 0;
        int m = 0;
 
        while (scan.hasNextDouble()) {
            double x = scan.nextDouble();
            m = m + 1;
            sum = sum + x;
        }
 
        System.out.println(m + "个数的和为" + sum);
        System.out.println(m + "个数的平均值是" + (sum / m));
        scan.close();
    }
}

执行以上程序输出结果为(输入非数字来结束输入):

请输入数字:
12
23
15
21.4
end
4个数的和为71.4
4个数的平均值是17.85

7、BigDecimal类

package com.liuxiang.BigDecimal;

/**
 * double采用的是近似存储,近似却不等于,存在舍入误差。
 * 在一些需要高精度计算的行业,如银行,不能采用浮点值进行计算,应该使用Java写好的BigDecimal类
 */

public class ErrorDemo {
    public static void main(String[] args) {
        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);
    }
}
0.09999999999999998
0.9999999999999999
  • 位置: java.math包中。
  • 作用:精确计算浮点数。
  • 创建方式:BigDecimal bd=new BigDecimal (“1.0”);
  • 方法
    • BigDecimal add(BigDecimal bd) 加
    • BigDecimal subtract(BigDecimal bd) 减
    • BigDecimal multiply(BigDecimal bd) 乘
    • BigDecimal divide(BigDecimal bd) 除
    • BigDecimal divide(BigDecimal bd,int scal, RoundingMode mode) 除
      • 参数scal:指定精确到小数点后几位。
      • 参数mode :指定小数部分的取舍模式,通常采用四舍五入的模式。取值为BigDecimal.ROUND_HALF_UP。

注意需要使用字符串作为输入值

package com.liuxiang.BigDecimal;

import javax.sound.midi.Soundbank;
import java.math.BigDecimal;

public class BigDecimalDemo {
    public static void main(String[] args) {
        //BigDecimal,大的浮点数精确计算
        BigDecimal bigDecimal = new BigDecimal("1.0");
        BigDecimal bigDecimal1 = new BigDecimal("0.9");
        //减法
        System.out.println(bigDecimal.subtract(bigDecimal1));
        //加法
        System.out.println(bigDecimal.add(bigDecimal1));
        //乘法
        System.out.println(bigDecimal.multiply(bigDecimal1));
        //除法
        BigDecimal bigDecimal2 = new BigDecimal("1.4").subtract(new BigDecimal("0.5")).divide(new BigDecimal("0.9"));
        System.out.println(bigDecimal2);

        //10/3除不尽时需要告诉保留几位小数,BigDecimal.ROUND_HALF_UP表示四舍五入
        BigDecimal bigDecimal3 = new BigDecimal("10").divide(new BigDecimal("3"),5,BigDecimal.ROUND_HALF_UP);
        System.out.println(bigDecimal3);
    }
}
0.1
1.9
0.90
1
3.33333

8、Date类

  • Date表示特定的瞬间,精确到毫秒。Date类中的大部分方法都已经被Calendar类中的方法所取代。
  • 时间单位:1秒=1000毫秒,1毫秒=1000微秒,1微秒=1000纳秒
package com.liuxiang.Date;

import java.awt.dnd.DropTarget;
import java.util.Date;

public class DateDemo {
    public static void main(String[] args) {
        //1.创建 Date对象 今天
        Date date = new Date();
        System.out.println(date.toString());
        System.out.println(date.toLocaleString());//已过时

        //2.创建 Date对象 昨天
        Date date1 = new Date(date.getTime()-60*60*24*1000);//(1970年到现在的毫秒数) - (一天的毫秒数) = 昨天的时间
        System.out.println(date1.toString());
        System.out.println(date1.toLocaleString());//已过时

        //3.方法 after(); before();
        System.out.println(date.after(date1));
        System.out.println(date1.before(date));

        //4.比较 compareTo();
        int d = date.compareTo(date1);//今天减昨天为正数,输出1
        System.out.println(d);

        //比较是否相等 equals();
        System.out.println(date.equals(date1));
    }
}
Tue Jul 06 16:56:02 CST 2021
2021-7-6 16:56:02
Mon Jul 05 16:56:02 CST 2021
2021-7-5 16:56:02
true
true
1
false

9、Calendar类

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

  • 构造方法

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

package com.liuxiang.Calendar;

import java.util.Calendar;

public class CalendarDemo {
    public static void main(String[] args) {
        //创建Calendar对象
        Calendar calendar = Calendar.getInstance();
        System.out.println(calendar.toString());
        System.out.println(calendar.getTime().toLocaleString());//获取现在时间
        System.out.println(calendar.getTimeInMillis());//获取1970年到现在的毫秒值

        //获取时间信息
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);//HOUR12小时 HOUR_OF_DAY24小时
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        System.out.println(year+"年 "+(month+1)+"月 "+day+"日 "+hour+"时 "+minute+"分 "+second+"秒 ");//month范围0-11

        //修改时间
        Calendar calendar1 = Calendar.getInstance();
        calendar1.set(Calendar.DAY_OF_MONTH,5);
        System.out.println(calendar1.getTime().toLocaleString());

        //add方法修改时间
        calendar1.add(Calendar.HOUR,1);
        System.out.println(calendar1.getTime().toLocaleString());

        //补充方法:getActualMaximum(); getActualMinimum();
        int max = calendar1.getActualMaximum(Calendar.DAY_OF_MONTH);//当前calendar1这一个月的天数最大值
        System.out.println(max);
        int min = calendar1.getActualMinimum(Calendar.DAY_OF_MONTH);//当前calendar1这一个月的天数最小值
        System.out.println(min);
    }
}
java.util.GregorianCalendar[time=1625563862337,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=31,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2021,MONTH=6,WEEK_OF_YEAR=28,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=187,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=31,SECOND=2,MILLISECOND=337,ZONE_OFFSET=28800000,DST_OFFSET=0]
2021-7-6 17:31:02
1625563862337
2021年 7月 6日 17时 31分 2秒 
2021-7-5 17:31:02
2021-7-5 18:31:02
31
1

10、SimpleDateFormat类

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

)

package com.liuxiang.SimpleDateFormat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatDemo {
    public static void main(String[] args) throws ParseException {
        //创建SimpleDateFormat对象 y->年 M->月 d->日 H->时 m->分 s->秒 S->毫秒
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        //创建Date
        Date date = new Date();
        //格式化date(把日期转成字符串)
        String str = sdf.format(date);
        System.out.println(str);
        //解析(把字符串转成日期)
        Date date1 = sdf.parse("1999年12月03日 12:12:12");
        System.out.println(date1);
    }
}
2021年07月06日 17:48:13
Fri Dec 03 12:12:12 CST 1999

11、System类

  • System系统类,主要用于获取系统的属性数据和其他操作,构造方法私有的。

package com.liuxiang.System;

import java.util.Arrays;

public class SystemDemo {
    public static void main(String[] args) {
        //System.arraycopy() 数组的复制
        //src:源数组
        //srcPos:从哪个位置开始复制
        //dest:目标数组
        //destPos:目标数组的位置
        //length:复制的长度
        int[] arr = {1,2,3,4,5,6,7,8};
        int[] dest = new int[8];
        System.arraycopy(arr,0,dest,0,arr.length);
        System.out.println(Arrays.toString(dest));

        //System.currentTimeMillis() 获取当前系统时间,返回的是毫秒值
        System.out.println(System.currentTimeMillis());//1970年1月1日到现在的毫秒数
        long start = System.currentTimeMillis();
        for (int i = -99999999; i < 99999999; i++) {
            for (int j = -99999999; j < 99999999; j++) {
                int result = i+j;
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("用时:"+(end-start));

        //System.gc() 建议JVM赶快启动垃圾回收器回收垃圾
        System.gc();

        //System.exit() 退出jvm,如果参数是0表示正常退出jvm,非0表示异常退出jvm
        System.exit(0);
        System.out.println("程序结束了...");//提前退出JVM,此行代码不执行
    }
}
[1, 2, 3, 4, 5, 6, 7, 8]
1625566406314
用时:7
posted @ 2021-07-06 18:52  有一个大佬梦  阅读(173)  评论(0)    收藏  举报