Java常用类介绍,内部类,Object类,包装类等

183 阅读17分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情


前言

本文将为大家对为Java常用类进行详细介绍,详细内容包括:内部类(包含成员内部类,静态内部类,局部内部类与匿名内部类),Object类,包装类,字符串,可变字符串,BigDecimal,Data,日历类等,包含对所有常用的Java类的相关知识与使用分享。

Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~

一、内部类

首先我们来看一看内部类的定义,以及有哪些内部类。

  • 定义在类的内部的类叫做内部类。
  • 内部类的作用一般是用来封装在类的内部使用的类,不希望外部被其他类所使用。

1.分类

可将内部类进行细分,可分为四类:成员内部类,静态内部类,局部内部类与匿名内部类。

  • 成员内部类:直接在类的内部定义的类
  • 静态内部类:直接在类的内部定义的前面加上static关键字的类
  • 局部内部类:在方法中定义的类
  • 匿名内部类:没有类的名称,只使用一次的类

2.成员内部类

我们来看一下对于成员内部类的使用。

  • 使用方式等同于成员变量的使用方式
public class A {
    int i = 3;
    public class B{
        public String n;
    }
    public void m() {
        B b = new B();
    }
}

public class Test {
    public static void main(String[] args) {
        A a = new A();
        a.i = 3;
        A.B b = new A().new B();
        b.n = "Hello";
        System.out.println(b.n);
    }
}
  • 成员内部类与外部类的相互调用
  • 内部类不能定义静态属性,但是可以定义静态常量,需要直接赋值
public class A {
    int i = 3;
    // 在外部类可以创建对象调用内部类
    public void m() {
        B c = new B();
        System.out.println(i);
        System.out.println(c.n);
        c.b();
    }
    public class B{
        public String n;
        int i = 5;
        // 内部类可以直接调用外部类
        public void b() {
            System.out.println(n);
            System.out.println(i); // 调用当前类的i属性
            System.out.println(A.this.i);  // 如果属性名称相同,调用外部的i属性
//            m();
        }
    }
}

3.静态内部类

然后是静态内部类,静态内部类 在类之前有static修饰符。

  • 在类的内部定义的使用static修饰的类
  • 注意:静态内部类中无法访问外部类的实例相关的内容

下边代码展示了静态内部类的示例。

public class StaticA {
    public static String count;
    public String a;
    public static class StaticB{
        public String name;
        public static int i;
        public void m() {
//            System.out.println(StaticA.this.a); // 无法访问外部类的成员
            System.out.println(count);
        }
        public static void sm() {
            System.out.println(count);
        }
    }
}
public static void main(String[] args) {
    StaticA.count = "5";
    StaticA.StaticB staticB =  new StaticA.StaticB(); // 使用外部类的类名来引用内部类的构造方法
}

4.局部内部类

接下来是局部内部类,局部内部类类似于局部变量,只能在当前的类中才能被使用。

  • 在一个方法中定义的类,只能在该方法中创建对象并使用
public class C {
    public String name = "aaa";
    public void m1() {
        class D{ // 局部内部类的使用
            int n = 5;
            public void d() {
                System.out.println(n);
                System.out.println(name);
            }
        }
        D d = new D(); // 创建对象
        d.n = 10;
        d.d();
    }
    public void m2() {
    }
}

5.匿名内部类

最后是匿名内部类。

  • 一般是将接口使用new关键字在创建对象时进行一个匿名实现

匿名内部类的作用是,在项目中,存在有些类我们只需要创建一个对象,此时就可以使用匿名内部类。(单例模式最好的解决方法就是使用此方案<内部类的方式>)

public interface MyInter {
    void method();
    void m1();
}
public static void main(String[] args) {
    MyInter m = new MyInter() {
        @Override
        public void method() {
            System.out.println(&quot;method&quot;);
        }
        @Override
        public void m1() {
            System.out.println(&quot;m1&quot;);
        }
    };
    m.method();
}

二、Object类

然后来了解一下Object类。Object类是所有类的父类,所有的类都可以使用Object类的方法。

Class Object是类Object结构的根。 每个类都有Object作为超类。 所有对象(包括数组)都实现了这个类的方法。 下面我们来看看Object类包含有哪些方法:

Object中的方法:

  • clone():克隆
  • equals(Object obj):比较
  • getClass():获得对象类型
  • hashCode():返回对象的哈希码值
  • finalize():垃圾回收
  • toString():返回对象的字符串表示形式
  • notify():唤醒正在等待对象监视器的单个线程
  • notifyAll():唤醒正在等待对象监视器的所有线程
  • wait():导致当前线程等待,直到另一个线程调用该对象的notify()或notifuAll()方法

我们需要注意的是,其中的equals()方法是用来比较内存地址的,如果我们在比较的时候想要比较值则需要重写equals()方法,或者使用“==”!

判断一个对象是否是某个类型的两种方式:

getClass()可以获得 对象类型,可以对于某个对象类型进行判断,另外也可以使用instanceof操作符。

if(obj3 instanceof Cat) {
    System.out.println(&quot;obj3是cat类的对象&quot;);
}
if(obj2.getClass() == Dog.class) {
    System.out.println(&quot;obj2是dog类的对象&quot;);
}

hashCode():通过对象的地址或者其他信息根据hash算法计算出来的一个数字,有利于对象在内存中的查找、排序、比较等。相同的对象应该保证其hashCode相同,不同的对象尽可能保证hashCode不同。

toString():默认显示当前对象类型和其hashCode,意义不大。一般情况下,在我们自定义的类中,都会对toString方法进行重写,以使用toString方法输出更多的信息。

public class Animal {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return &quot;Animal [name=&quot; + name + &quot;]&quot;;
    }
}

equals方法用来比较两个对象是否是相同的对象,事实上比较的是两个对象的地址,如果它们的 地址一样自然是同一个对象。由于在Object中equals方法是默认为用==比较,所以在实际项目中,应该重写equals方法,然而相同的对象应该有相同的hashCode,所以重写equals方法的同时也应该重写hashCode方法。

以下代码展示了euqals方法与“==”进行比较的用法与区别。

public class Animal {
    private String id;
    private String name;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return &quot;Animal [name=&quot; + name + &quot;]&quot;;
    }
    @Override
    public boolean equals(Object obj) {
        if(obj == null) { // 对象是否为空
            return false;
        }
        if(this == obj) { // 是否同一个地址
            return true;
        }
        if(obj instanceof Animal) { // 是否同一个类型
            Animal a = (Animal)obj;
            if(a.id == null) {
                return false;
            }
            if(this.id .equals(a.id) ) {
                return true;
            }else {
                return false;
            }
        }else {
            return false;
        }
    }
    @Override
    public int hashCode() {
        return id.hashCode();
    }
}

三、包装类

下面来看看什么是包装类。

在Java中基本数据类型对应的引用数据类型,叫包装类

下面是对于包装类的代码示例。

public static void main(String[] args) {
    // JDK1.5之前的写法
    int i = 3;
    Integer in = new Integer(i); // 装箱
    Object obj = in;
    int i2 = in.intValue(); // 拆箱
    // JDK1.5之后,自动装箱拆箱
    Integer in1 = i; // 自动装箱
    int i3 = in1; // 自动拆箱
    Double d = 0.3;
    double db = d;
    // 将字符串转换成基本数据类型
    String s = &quot;3&quot;;
    // 如果该字符串里面不是数字,将会出现NumberFormatException
    int n = Integer.valueOf(s); // parseInt()也行
    System.out.println(n);
    String s1 = &quot;2.04&quot;;
    double db1 =  Double.parseDouble(s1);
    System.out.println(db1);
    // 如果该字符串中不是true(不区分大小写),则返回false,不论如何不会报错
    String s2 = &quot;TRue&quot;;
    boolean b = Boolean.parseBoolean(s2);
    System.out.println(b);
    // 对于char类型,直接使用charAt(index)
    String s3 = &quot;ABCD&quot;;
    char c = s3.charAt(2);
    System.out.println(c);
    int m = 50;
    int m1 = 50;
    System.out.println(m == m1);
    // Integer常量池(缓冲区)
    // 在Integer中,最多会设置-128到127,一共256个常量
    // 在使用valueOf或者直接以数字的形式赋值时,会去常量池中查找,如果能找到,则返回该常量,否则或创建一个对象
    // 如果是常量池中的常量,使用再多次,也是用的同一个地址
    Integer in2 = 100;
    Integer in3 = 100;
    System.out.println(in2 == in3); // true
    Integer in4 = 200;
    Integer in5 = 200;
    System.out.println(in4 == in5); // false
    Integer in6 = new Integer(100);
    Integer in7 = new Integer(100);
    System.out.println(in6 == in7); // false
    Integer in8 = Integer.valueOf(100);
    Integer in9 = Integer.valueOf(100);
    System.out.println(in8 == in9); // true
    Integer in10 = Integer.valueOf(200);
    Integer in11 = Integer.valueOf(200);
    System.out.println(in10 == in11); // false
}

四、字符串

下面来看看Java中的字符串,Java中的字符串事实上也是对象,也就是说对于一个字符串创建了以后,它在内存中是不变的,当我们后边再使用相同字符串的时候使用的其实是内存中的同一个的对象。所以对于字符串对象具有以下特点:

  • String对象创建后不可变,是指String内部使用一个final char[]来存放数据。所以值不能改变。
  • String每次重新赋值相当于重新的创建了字符串。
String s = &quot;hello&quot;;
s = &quot;world678&quot;;
System.out.println(s);
  • 对于字符串有两种赋值方式: String s = “hello”; String s1 = new String(“world”);
  • 字符串常量池,在内存中,会分配一块空间,里面存放字符串常量,当使用""来给字符串赋值时,会在常量创建该字符串,如果变量直接用等于接收,即变量中存储的是该常量的地址,而该常量可以复用,所以下面第一个表达式的值为true,即都指向常量池中的同一个区域。
  • 而如果通过new String来创建对象,会分配一个块新的空间,所以下面的第二个表达式值为false。
String s1 = &quot;hello&quot;;
String s2 = &quot;hello&quot;;
System.out.println(s1 == s2); // true
String s3 = new String(&quot;hello&quot;);
String s4 = new String(&quot;hello&quot;);
System.out.println(s3 == s4); // false
  • 字符串的常量优化:(编译期优化)
  • 如果字符串在编译时,能确定值,并且不会变化,则会进行优化,直接在编译时直接得到结果,而不会在运行时再计算。
String s5 = &quot;ab&quot;;
String s6 = &quot;a&quot; + &quot;b&quot;;
System.out.println(s5 == s6); // true
String s7 = &quot;a&quot;;
String s8 = s7 + &quot;b&quot;;
System.out.println(s5 == s8); // false
final String s9 = &quot;a&quot;;
String s10 = s9 + &quot;b&quot;;
System.out.println(s5 == s10); // true

以下代码 总结展示了字符串的所有常用方法,包括判断一个字符串是否包含某个子串;将字符串转换成char数组;计算字符串的长度;去掉字符串两边的空格;将字符串全部大写;将字符串全部小写;判断字符串是否以xx开始;判断字符串是否以xx结尾;将字符串中出现h全部替换成ooo;将字符串根据“,”切割成一个字符串数组等一系列方法。

public static void main(String[] args) {
    // 得到字符某个位置的字符
    String s = &quot;hello&quot;;
    char ch = s.charAt(1); // 结果为e
    String s1 = &quot;oh, hello, hello&quot;;
    boolean b = s1.contains(s); // 结果是true,s1字符串中包含s
    System.out.println(b);
    char [] arr = s1.toCharArray(); // 将字符串转换成char数组
    System.out.println(Arrays.toString(arr));
    int index = s1.indexOf(s); // 判断s1中是否包含s,如果包含则返回s第一次出现的下标,如果不包含,则返回-1
    System.out.println(index);
    // 注意:数组的长度为length属性,字符串是length方法
    System.out.println(s1.length()); // length方法返回字符串的长度
    String s2 = &quot;       hello       &quot;;
    System.out.println(s2);
    System.out.println(s2.length());
    String newS2 = s2.trim(); // 去掉字符串两边的空格
    System.out.println(newS2);
    System.out.println(newS2.length());
    String newS1 = s1.toUpperCase(); // 将字符串全部大写
    System.out.println(newS1);
    newS1 = newS1.toLowerCase(); // 将字符串全部小写
    System.out.println(newS1);
    boolean b1 = s1.startsWith(&quot;oh,&quot;); // 判断字符串是否以xx开始
    System.out.println(b1);
    b1 = s1.endsWith(&quot;oh,&quot;); // 判断字符串是否以xx结尾
    System.out.println(b1);
    String newS3 = s1.replace(&quot;h&quot;, &quot;ooo&quot;); // 将字符串中出现h全部替换成ooo
    System.out.println(newS3);
    String [] strArr = s1.split(&quot;,&quot;); // 将字符串根据,切割成一个字符串数组
    System.out.println(strArr.length);
    System.out.println(Arrays.toString(strArr));
    String s4 = &quot;abcdefghijkllmn&quot;;
    String newS4 = s4.substring(3); // 从第三号位置开始截取,截取后面所有的字符串
    System.out.println(newS4);
    newS4 = s4.substring(3, 6); // 从第三号位置开始截取,截取到6号位置(不包含6号位置)
    System.out.println(newS4);
    byte [] bytes = s5.getBytes(); // 得到所有的字节形成的字节数组
    System.out.println(Arrays.toString(bytes));
}
  • 注意: 如果该方法是用来改变字符串,一定会返回一个新的字符串,因为字符串不能直接改变 。

五、可变字符串

一般的字符串定义以后在内存中是不可变的,那是用String类定义的字符串,事实上,Java中也提供了定义可变字符串的类——StringBuffer,使用StringBuffer定义的字符串我们在后期的使用过程中如果想想要改变其大小是可以的,可以通过insert()与delete()实现对字符串的修改操作。

  • 可变字符串可以对字符串进行增删改操作,主要作用是当要大量的操作字符串的时候,应该使用可变字符串,以提升性能,节约空间。
  • StringBuffer:JDK1.0提供,线程安全,效率低
  • StringBuilder:JDK5.0提供,线程不安全,效率高
// 创建StringBuilder或StringBuffer
StringBuilder sb = new StringBuilder(&quot;hello&quot;);
// 拼接字符串
sb.append(&quot;world&quot;);
sb.append(&quot;world&quot;);
sb.insert(2, &quot;aaa&quot;); // 向第二号位插入内容
sb.delete(3, 6); // 从第3号位删除到第6号位(不包含6号位)
System.out.println(sb.toString());

六、BigDecimal

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、×、 /等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

  • 通常用来进行小数精确运算和大数字的计算。
  • 注意:构造方法一定要使用字符串的方式。
public static void main(String[] args) {
    //        System.out.println(1.0-0.9); // 不精确
    //        System.out.println(2100000000 * 2100000000 * 2100000000); // 超出范围
    BigDecimal b = new BigDecimal(&quot;1.0&quot;);
    BigDecimal b1 = new BigDecimal(&quot;0.9&quot;);
    System.out.println(b.subtract(b1)); // 减法
    BigDecimal b2 = new BigDecimal(&quot;1.0234279243253&quot;);
    BigDecimal b3 = new BigDecimal(&quot;0.91231231234&quot;);
    System.out.println(b2.multiply(b3)); // 乘法
    BigDecimal b4 = new BigDecimal(&quot;1.0234279243253&quot;);
    BigDecimal b5 = new BigDecimal(&quot;0.91231231234&quot;);
    // 参数1,数
    // 参数2,保留小数位
    // 参数3,此处选择的四舍五入
    System.out.println(b4.divide(b5, 2000, BigDecimal.ROUND_HALF_UP));// 除法
    // 大数字的运算
    BigDecimal b6 = new BigDecimal(&quot;428374892734927347892749827498273947298374927344&quot;);
    BigDecimal b7 = new BigDecimal(&quot;548347593754892874823472938748237875984359374859&quot;);
    System.out.println(b6.multiply(b7));
}

七、Date

初步使用:

// 不能引入错误的包哈
import java.util.Date;
public class DateTest {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date);
    }
}

结果:
Mon Aug 09 15:46:13 GMT+08:00 2021
// 这是美国表示时间的方法

GMT(Greenwich Mean Time)是格林尼治标准时间 ,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治时)的时间。

+08:00 就是北京时间,这是时间区域的标示,用以区别时间,以英国格林威治标准时间为基准,台湾,香港,中国为往东8个时区。

  • Date是非常常用的一个日期时间类,可以得到当前时间,与其他的时间比较早晚。

对于Data类的使用代码示例总结如下:

public static void main(String[] args) {
    Date d = new Date(); // 得到当前时间对象,有时区
    // 得到距离1970-1-1 GMT 0:0:0 所经过的毫秒数
    System.out.println(d.getTime()); 
    d.setTime(1597046465956L); // 设置时间为2020-8-10 16:01:05 CST
    System.out.println(d);
    Date d1 = new Date();
    System.out.println(d.before(d1)); // 判断d是否在d1之前
    System.out.println(d.after(d1)); // 判断d是否在d1之后
    int n = d.compareTo(d1); // d如果早于d1,返回-1,等于返回0,晚于返回1
    System.out.println(n);
}

八、日历类

  • 一个相对比较新的日期类,Calendar是一个抽象类,它本身就是日历的意思
  • 日历类主要作用是对日期进行获取和设置,并进行加减。

Calendar类是一个日历抽象类,提供了一组对“年月日时分秒星期”等日期信息的操作的函数,并针对不同国家和地区的日历提供了相应的子类,即本地化。比如公历GregorianCalendar,佛历BuddhistCalendar,日本帝国历JapaneseImperialCalendar等。

从JDK1.1版本开始,在处理日期和时间时,系统推荐使用Calendar类进行实现(Date的一些方法都过时了)。在设计上,Calendar类的功能要比Date类强大很多,而且在实现方式上也比Date类要复杂一些,下面就介绍一下Calendar类的使用。

以下是对于Calendar类的使用代码示例:

public static void main(String[] args) {
    // 得到对象,不能使用new创建对象
    Calendar c = Calendar.getInstance();
    // 获取日期
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int date = c.get(Calendar.DATE);
    int hour = c.get(Calendar.HOUR_OF_DAY);// 24小时制
    int minute = c.get(Calendar.MINUTE);
    int second = c.get(Calendar.SECOND);
    int weekday = c.get(Calendar.DAY_OF_WEEK); // 日一二三
    System.out.println(year + &quot;年&quot; + (month+1) + &quot;月&quot; + date + &quot;日 &quot; +
                       hour + &quot;:&quot; + minute + &quot;:&quot; + second + &quot; 星期&quot; + weekday);
    // 日期计算
    // 参数1:日期计算的标准(日,月,年,星期,小时等)
    // 参数2:时长(可以使用负数)
    c.add(Calendar.WEEK_OF_YEAR, -60);
    System.out.println(c);
}

创建一个当时的时间对象,就是new的那一瞬间,精确到毫秒。

创建一个时间对象,需要传入一个时间戳,代表时间戳表示的时间。其实我们能看到,Date中的很多的构造器已经被启用了,只留下几个常用的。但是我们不能否认Date是十分常用的一个类。

九、SimpleDateFormat

SimpleDateFormat相当于是针对时间的一个工具类,可以实现将字符串转换成日期类型,以及照提供的格式将日期转换成字符串显示。

  • 主要作用是将日期格式化成字符串,或将字符串转换成日期格式。
public static void main(String[] args) {
    String s = &quot;1999101014:25:36.175&quot;;
    // yyyy 年
    // MM 月
    // dd 日
    // HH 24制小时 
    // hh 12小时制
    // mm 分钟
    // ss 秒
    // SSS 毫秒
    SimpleDateFormat sdf = new SimpleDateFormat(&quot;yyyy年MM月dd日 HH:mm:ss.SSS&quot;);
    try {
        Date date = sdf.parse(s); // 将字符串转换成日期类型
        System.out.println(date);
    } catch (ParseException e) {
        // 如果出错会执行输出异常原因
        e.printStackTrace();
    } 
    Date d = new Date();
    SimpleDateFormat sdf1 = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);
    String str = sdf1.format(d); // 按照提供的格式将日期转换成字符串显示
    System.out.println(str);
} = 'bar';

十、System类的常见方法

System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。由于该类的构造方法是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员方法和成员变量都是static(静态)的,所以也可以很方便的调用他。

System中包含了in、out和err三个成员变量,分别代表标准输入流(键盘输入)、标准输出流(显示器)和标准错误输出流(显示器)。

System中常用的方法:

  • arrayCopy() :数组复制
  • currentTimeMillis():得到当前时间的毫秒数
  • gc():建议JVM启动垃圾回收
  • exit(0):退出系统
public static void main(String[] args) {
    // 得到当前时间距离1970-1-1 0:0:0 GMT的毫秒数
    System.out.println(System.currentTimeMillis());
    for (int i = 0; i &lt; 100; i++) {
        if(i == 20) {
            System.exit(0); // 退出系统
        }
        System.out.println(i);
    }
}

后记

以上呢就是为大家分享的对于Java常用类的详细介绍,包括了:内部类(包含成员内部类,静态内部类,局部内部类与匿名内部类),Object类,包装类,字符串,可变字符串,BigDecimal,Data,日历类,ystem类的常见方法等,包含对所有常用的Java类的相关知识与使用。希望本文的分享能够使你有所收获。如果你想继续深入学习Java相关的知识和技术,可以参考:

Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~

看完不关注就想跑.gif