zoukankan      html  css  js  c++  java
  • Java之常用类(一)

    在之前我们学习了关于Java基础以及面向对象基础的知识,基本上已经是进入到Java的大门之中了。从现在开始就可以就可以学习更多的关于Java语言的更复杂更常用的知识,那么这一篇博客我们就来聊一聊Java中的常用类,会给大家介绍一下日后学习和工作都会用到的一些Java常用类,在一定程度上可以帮助我们更高效的学习和工作。

    Object类

    在之前的学习中就已经提到过了,Object类是所有类的父类,任何类都默认继承Object。他是所有类的祖先。

    理论上Object类是所有类的父类,即直接或间接的继承Java.lang.Object类

    由于所有的类都继承Object类,因此省略了extends Object关键字。

    该类中主要有以下方法:

      toString()

      getClass()

      equals()

      clone()

      finalize()

      其中toString(),getClass(),equals()方法是相对来说比较重要的

    【演示:查看Object类源码】

    注意: Object类中的getClass(),notify(),notifyAll(),wait()等方法被定义为final类型,因此不能重写。

    1、clone()方法

    protected native Object clone() throws CloneNotSupportedException;

    clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。那么在java语言中,有几种方式可以创建对象呢?

      使用new操作符创建一个对象

      使用clone方法复制一个对象

    那么这两种方式有什么不同之处呢?

      new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后, 再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。

      而clone在第一步 是和new相似的, 都是分配内存,调用clone方法时,分配的内存和原对象(即调用clone方法的对象) 相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

    clone与copy的区别

      假设现在有一个Employee对象,Employee tobby =new Employee(“CMTobby”,5000)

      通常我们会有这样的赋值Employee cindyelf=tobby,这个时候只是简单了copy了一下reference(引用), cindyelf和tobby都指向内存中同一个object,这样cindyelf或者tobby的一个操作都可能影响到对方。打 个比方,如果我们通过cindyelf.raiseSalary()方法改变了salary域的值,那么tobby通过getSalary()方法 得到的就是修改之后的salary域的值,显然这不是我们愿意看到的。我们希望得到tobby的一个精确拷贝,同时两者互不影响,这时候, 我们就可以使用Clone来满足我们的需求。

      Employee cindy=tobby.clone(),这时会生成一个新的Employee对象,并且和tobby具有相同的属性值和方法。

    Shallow Clone和Deep Clone

      主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用,我们有时候不希望在方法里将参数改变,这是就需要在类中复写clone方法(实现深复制)。

      Clone是如何完成的呢?Object在对某个对象实施Clone时对其是一无所知的,它仅仅是简单地执行域对域的copy,这就是Shallow Clone。这样,问题就来了咯。

      以Employee为例,它里面有一个域hireDay不是基本数据类型的变量,而是一个reference变量,经过Clone之后就会产生一个新的Date型的reference,

      它和原始对象中对应的域指向同一个Date对象,这样克隆类就和原始类共享了一部分信息,而这样显然是不利的,过程下图所示:

    这个时候我们就需要进行deep Clone了,对那些非基本类型的域进行特殊的处理,例如本例中的 hireDay。我们可以重新定义Clone方法(实现Cloneable中的clone()方法),对hireDay做特殊处理,如下代码所示:

    1 class Employee implements Cloneable {
    2     public Object clone() throws CloneNotSupportedException {
    3         Employee cloned = (Employee) super.clone();
    4         cloned.hireDay = (Date) hireDay.clone()
    5         return cloned;
    6     }
    7 }

    clone方法的保护机制

      在Object中Clone()是被声明为protected的,这样做是有一定的道理的,以Employee类为例,通过声明为protected,就可以保证只有Employee类里面才能“克隆”Employee对象.

    clone方法的使用

      什么时候使用shallow Clone,什么时候使用deep Clone,这个主要看具体对象的域是什么性质的,基本类型还是reference variable

      调用Clone()方法的对象所属的类(Class)必须implements Clonable接口,否则在调用Clone方法的时候会抛出CloneNotSupportedException

    2、toString()方法

     Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@” 和此对象哈希码的无符号十六进制表示组成。

     该方法用得比较多,一般子类都有覆盖。

    我们推荐在学习阶段所有有属性的类都加上toString() 方法!

    1 public class test {
    2     public static void main(String[] args) {
    3         Object object = new Object();
    4         String s = object.toString();
    5         System.out.println(s);
    6     }
    7 }

     3、getClass方法

     返回次Object的运行时类类型。

    不可重写,要调用的话,一般和getName()联合使用,如getClass().getName();

    1 public class test {
    2     public static void main(String[] args) {
    3         Object object = new Object();
    4         Class<?> aClass = object.getClass();
    5         System.out.println(aClass);
    6     }
    7 }

     4、finalize()方法

    1  protected void finalize() throws Throwable { }

    该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。

    Java允许在类中定义一个名为finalize()的方法。它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。

     finalize()的用途:

    无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。

    这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。不过这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。

    5、equals()方法

    1  public boolean equals(Object obj) {
    2         return (this == obj);
    3  }

    Object中的equals方法是直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参 obj所引用的对象是否是同一对象,所谓同一对象就是指内存中同一块存储单元,如果this和obj指向的hi同一块内存对象,则返回true,如果 this和obj指向的不是同一块内存,则返回false。

    注意:即便是内容完全相等的两块不同的内存对象,也返回false。

    如果是同一块内存,则object中的equals方法返回true,如果是不同的内存,则返回false

    如果希望不同内存但相同内容的两个对象equals时返回true,则我们需要重写父类的equal方法

    String类已经重写了object中的equals方法(这样就是比较内容是否相等了)

    【我们可以查看String类中重写equals的方法】

     1 public boolean equals(Object anObject) {
     2         if (this == anObject) {
     3             return true;
     4         }
     5         if (anObject instanceof String) {
     6             String anotherString = (String)anObject;
     7             int n = value.length;
     8             if (n == anotherString.value.length) {
     9                 char v1[] = value;
    10                 char v2[] = anotherString.value;
    11                 int i = 0;
    12                 while (n-- != 0) {
    13                     if (v1[i] != v2[i])
    14                         return false;
    15                     i++;
    16                 }
    17                 return true;
    18             }
    19         }
    20         return false;
    21     }

    6、hashCode方法

    1 public native int hashCode();

    返回该对象的哈希码值。

    该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写 hashCode方法。这个方法在一些具有哈希功能的Collection中用到。

    一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash Code() == obj2.hashCode(),但是 hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。

    7、wait()方法

     1 public final native void wait(long timeout) throws InterruptedException;
     2 
     3 ====================================
     4 
     5  public final void wait(long timeout, int nanos) throws InterruptedException {
     6         if (timeout < 0) {
     7             throw new IllegalArgumentException("timeout value is negative");
     8         }
     9 
    10         if (nanos < 0 || nanos > 999999) {
    11             throw new IllegalArgumentException(
    12                                 "nanosecond timeout value out of range");
    13         }
    14 
    15         if (nanos > 0) {
    16             timeout++;
    17         }
    18 
    19         wait(timeout);
    20     }
    21 
    22 =====================================
    23 public final void wait() throws InterruptedException {
    24         wait(0);
    25 }

    可以看到有三种重载,wait什么意思呢?

     方法中的异常:

    wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。

    wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,

    如果在规定时间内没有获得锁就返回。

    调用该方法后当前线程进入睡眠状态,直到以下事件发生。

    (1)其他线程调用了该对象的notify方法。

    (2)其他线程调用了该对象的notifyAll方法。

    (3)其他线程调用了interrupt中断该线程。

    (4)时间间隔到了。

    此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。

    8、notify()方法

     该方法唤醒在该对象上等待的某个线程。

     该方法唤醒在该对象上等待的所有线程。

    包装类

    1、包装类介绍

    虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备“对象”的特性——不携带属性、没有方法可调用。 沿用它们只是为了迎合人类根深蒂固的习惯,并的确能简单、有效地进行常规数据处理。

    这种借助于非面向对象技术的做法有时也会带来不便,比如引用类型数据均继承了 Object 类的特性,要转换为 String 类型(经常有这种需要)时只要简单调用 Object 类中定义的toString()即可,而基本数据 类型转换为 String 类型则要麻烦得多。为解决此类问题 ,Java为每种基本数据类型分别设计了对应的类,称之为包装类(Wrapper Classes),也有教材称为外覆类或数据类型类。

     每个包装类的对象可以封装一个相应的基本类型的数据,并提供了其它一些有用的方法。包装类对象一经创建,其内容(所封装的基本类型数据值)不可改变。

    基本类型和对应的包装类可以相互装换:

      由基本类型向对应的包装类转换称为装箱,例如把 int 包装成 Integer 类的对象;

      包装类向对应的基本类型转换称为拆箱,例如把 Integer 类的对象重新简化为 int。

    2、包装类的应用

    【1、实现int和Integer的相互转换】

    可以通过 Integer 类的构造方法将 int 装箱,通过 Integer 类的 intValue 方法将 Integer 拆箱。

    1     public static void main(String[] args) {
    2         int m = 500;
    3         Integer obj = new Integer(m); // 手动装箱
    4         int n = obj.intValue(); // 手动拆箱
    5         System.out.println("n = " + n);
    6         Integer obj1 = new Integer(500);
    7         System.out.println("obj 等价于 obj1?" + obj.equals(obj1));
    8     }

    其他的也同理

    【2、 将字符串转换为整数】

    Integer 类有一个静态的 paseInt() 方法,可以将字符串转换为整数,语法为:

    1 parseInt(String s, int radix);

    s 为要转换的字符串,radix 为进制,可选,默认为十进制。

    下面的代码将会告诉你什么样的字符串可以转换为整数:

     1     public static void main(String[] args) {
     2         String[] str = {"123", "123abc", "abc123", "abcxyz"};
     3         for(String str1 : str){
     4             try{
     5                 int m = Integer.parseInt(str1, 10);
     6                 System.out.println(str1 + " 可以转换为整数 " + m);
     7             }catch(Exception e){
     8                 System.out.println(str1 + " 无法转换为整数");
     9             }
    10         }
    11     }
    12 //结果
    13 123 可以转换为整数 123
    14         123abc 无法转换为整数
    15         abc123 无法转换为整数
    16         abcxyz 无法转换为整数

    【 3、将整数转换为字符串】

    Integer 类有一个静态的 toString() 方法,可以将整数转换为字符串。或者直接在整数后面加空字符串即 可!

    1     public static void main(String[] args) {
    2         int m = 500;
    3         String s = Integer.toString(m);
    4         String s2 = m+"";
    5         System.out.println("s = " + s);
    6     }

    3、自动拆箱和装箱

    上面的例子都需要手动实例化一个包装类,称为手动拆箱装箱。Java 1.5(5.0) 之前必须手动拆箱装箱。

    Java 1.5 之后可以自动拆箱装箱,也就是在进行基本数据类型和对应的包装类转换时,系统将自动进 行,这将大大方便程序员的代码书写。

     自动装箱与拆箱的功能事实上是编译器来帮您的忙,编译器在编译时期依您所编写的语法,决定是否进行装箱或拆箱动作。例如:

    1 Integer i = 100;
    2 相当于编译器自动为您作以下的语法编译:
    3 Integer i = new Integer(100);

    所以自动装箱与拆箱的功能是所谓的“编译器蜜糖”(Compiler Sugar),虽然使用这个功能很方便,但在程序运行阶段您得了解Java的语义。例如下面的程序是可以通过编译的:

    1 Integer i = null;
    2 int j = i;

    这样的语法在编译时期是合法的,但是在运行时期会有错误,因为这种写法相当于:

    1 Integer i = null;
    2 int j = i.intValue();

    null表示i 没有参考至任何的对象实体,它可以合法地指定给对象参考名称。由于实际上i并没有参考至任 何的对象,所以也就不可能操作intValue()方法,这样上面的写法在运行时会出现NullPointerException 错误。

    自动拆箱装箱是常用的一个功能,需要重点掌握

    一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte、int、long、double 等。然 而,在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。为了解决这个问 题,Java 语言为每一个内置数据类型提供了对应的包装类。

    所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。

    Math类

    Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。

    Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。

    【演示:查看Math类的源码】

     【常用值与函数】

    Math.PI 记录的圆周率

    Math.E 记录e的常量

    Math中还有一些类似的常量,都是一些工程数学常用量。

    Math.abs 求绝对值

    Math.sin 正弦函数

    Math.asin 反正弦函数

    Math.cos 余弦函数

    Math.acos 反余弦函数

    Math.tan 正切函数

    Math.atan 反正切函数

    Math.atan2 商的反正切函数

    Math.toDegrees 弧度转化为角度

    Math.toRadians 角度转化为弧度

    Math.ceil 得到不小于某数的最大整数

    Math.floor 得到不大于某数的最大整数

    Math.IEEEremainder 求余

    Math.max 求两数中最大

    Math.min 求两数中最小

    Math.sqrt 求开方

    Math.pow 求某数的任意次方, 抛出ArithmeticException处理溢出异常

    Math.exp 求e的任意次方

    Math.log10 以10为底的对数

    Math.log 自然对数 Math.rint 求距离某数最近的整数(可能比某数大,也可能比它小)

    Math.round 同上,返回int型或者long型(上一个函数返回double型)

    Math.random 返回0,1之间的一个随机数

     1 public static void main(String[] args) {
     2 /**
     3  *Math.sqrt()//计算平方根
     4  *Math.cbrt()//计算立方根
     5  *Math.pow(a, b)//计算a的b次方
     6  *Math.max( , );//计算最大值
     7  *Math.min( , );//计算最小值
     8  */
     9         System.out.println(Math.sqrt(16)); //4.0
    10         System.out.println(Math.cbrt(8)); //2.0
    11         System.out.println(Math.pow(3,2)); //9.0
    12         System.out.println(Math.max(2.3,4.5));//4.5
    13         System.out.println(Math.min(2.3,4.5));//2.3
    14 /**
    15  * abs求绝对值
    16  */
    17         System.out.println(Math.abs(-10.4)); //10.4
    18         System.out.println(Math.abs(10.1)); //10.1
    19 /**
    20  * ceil天花板的意思,就是返回大的值
    21  */
    22         System.out.println(Math.ceil(-10.1)); //-10.0
    23         System.out.println(Math.ceil(10.7)); //11.0
    24         System.out.println(Math.ceil(-0.7)); //-0.0
    25         System.out.println(Math.ceil(0.0)); //0.0
    26         System.out.println(Math.ceil(-0.0)); //-0.0
    27         System.out.println(Math.ceil(-1.7)); //-1.0
    28 /**
    29  * floor地板的意思,就是返回小的值
    30  */
    31         System.out.println(Math.floor(-10.1)); //-11.0
    32         System.out.println(Math.floor(10.7)); //10.0
    33         System.out.println(Math.floor(-0.7)); //-1.0
    34         System.out.println(Math.floor(0.0)); //0.0
    35         System.out.println(Math.floor(-0.0)); //-0.0
    36 /**
    37  * random 取得一个大于或者等于0.0小于不等于1.0的随机数 [0,1)
    38  */
    39         System.out.println(Math.random()); //小于1大于0的double类型的数
    40         System.out.println(Math.random()+1);//大于1小于2的double类型的数
    41 /**
    42  * rint 四舍五入,返回double值
    43  * 注意.5的时候会取偶数 异常的尴尬=。=
    44  */
    45         System.out.println(Math.rint(10.1)); //10.0
    46         System.out.println(Math.rint(10.7)); //11.0
    47         System.out.println(Math.rint(11.5)); //12.0
    48         System.out.println(Math.rint(10.5)); //10.0
    49         System.out.println(Math.rint(10.51)); //11.0
    50         System.out.println(Math.rint(-10.5)); //-10.0
    51         System.out.println(Math.rint(-11.5)); //-12.0
    52         System.out.println(Math.rint(-10.51)); //-11.0
    53         System.out.println(Math.rint(-10.6)); //-11.0
    54         System.out.println(Math.rint(-10.2)); //-10.0
    55 /**
    56  * round 四舍五入,float时返回int值,double时返回long值
    57  */
    58         System.out.println(Math.round(10.1)); //10
    59         System.out.println(Math.round(10.7)); //11
    60         System.out.println(Math.round(10.5)); //11
    61         System.out.println(Math.round(10.51)); //11
    62         System.out.println(Math.round(-10.5)); //-10
    63         System.out.println(Math.round(-10.51)); //-11
    64         System.out.println(Math.round(-10.6)); //-11
    65         System.out.println(Math.round(-10.2)); //-10
    66     }
  • 相关阅读:
    前端编程规范记录
    搬砖工坑爹教程
    JS的模块化编程学习之旅
    后端开发遇到的问题
    git学习中遇到的疑难杂症
    微信小程序填坑之旅
    详解Redis中两种持久化机制RDB和AOF
    redis系列:RDB持久化与AOF持久化
    Java中判断字符串是否为数字
    @Aspect 注解使用详解
  • 原文地址:https://www.cnblogs.com/koss/p/14494732.html
Copyright © 2011-2022 走看看