0
点赞
收藏
分享

微信扫一扫

Java复习笔记八

止止_8fc8 2022-04-02 阅读 56

#1.Java的常用类介绍

 

1.Object类

所有类的父类,所有类默认继承Object类,由于所有类都默认继承Object类,所以在写的时候可以省略extends Object。

方法有:

clone()方法:克隆一个对象,该对象与克隆对象之间的数据和存储空间互不干扰,彼此独立。

使用方法如下:

某类 对象 = 已存在对象.clone();

注在java语言中,有两个方法可以创建对象

一、使用new关键词创建

二、使用clone方法克隆对象

二者是有区别的,new是先申请一片储存空间,然后创建一个新的空对象,而clone()方法是对一个已经存在的对象进行克隆,且原对象和克隆后的对象,属性,方法是相同的,但本身是独立的,数据存储的位置不一样了。

clone()与copy()的区别:

clone()可以用工作指针来理解,此时clone()方法将新建一个employ对象,然后按照之前被克隆的对象,新建属性和方法,最后将一个新的指针指向克隆出来的对象,此时指针和对象都是独立的,和之前被克隆的对象独立无关。而copy()方法,相当于新建一个指针,指向复制对象,被复制对象一改变,跟着一起改变。

shallow clone 与deep clone

所谓shallow clone 字如其意,浅克隆,shallow clone在对object对象进行克隆时,只是把对象的属性和方法克隆了,但假如存在指向型的指针,假如现在有一个Employee对象,Employee tobby =new Employee("Tobby",5000),通常我们会有这样的赋值Employee cindyelf =tobby,这个时候只是简单的copy了一下reference,cindyelf和tobby都指向内存中同一个object,这样cindyelf或者tobby的一个操作都可能影响到对方,打个比方,如果我们通过cindyelf.raiseSalary()方法改变了salay域的值,那么tobby通过getSalary()方法 得到的就是修改之后的salary域的值,显然这不是我们愿意看到的。我们希望得到tobby的一个精确拷贝,同时两者互不影响,这时候, 我们就可以使用Clone来满足我们的需求。Employeecindy=tobby.clone(),这时会生成一个新的Employee对象,并且和tobby具有相同的属性值和方法。

主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用,我们有时候不希望在 方法里将参数改变,这是就需要在类中复写clone方法(实现深复制)。 Clone是如何完成的呢?Object在对某个对象实施Clone时对其是一无所知的,它仅仅是简单地执行域 对域的copy,这就是Shallow Clone。这样,问题就来了咯。 以Employee为例,它里面有一个域hireDay不是基本数据类型的变量,而是一个reference变量,经过 Clone之后就会产生一个新的Date型的reference,它和原始对象中对应的域指向同一个Date对象,这样克隆类就和原始类共享了一部分信息,而这样显然 是不利的。

这个时候我们就需要进行deep clone,对于那些非基本类型的域进行特殊的处理,例如本例中的hiryDay,我们就要对它进行特殊处理,如下:

class Employee implements CloneDeep
{
    public Object clone() throws CloneNotsupportedException{
        Employee cloned = (Employee) super.clone();
        clonee.hirDay=(Data)hirDay.clone();
        return cloned;
    }    
    
}

   

clone方法的保护机制

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

2.toString 方法

一个将类里所有信息转化为字符串的方法:

如下

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

在所有的类后打印时都可以使用这个方法:

public static void main (String[] args)
{
    Object o1 = new Obeject();
    System.out.println(ol.toString()); 
}

这样一转化,就可以将对象文件打印成String字符串了

3.getClass()方法

public final nactive Class <?> getclass();

getClass()方法用来返回Object 的运行时类型。

注:该方法无法被重写,一般与getName()方法联合使用,

public static void main(String[] args) {
Object o = new Object();
System.out.println(o.getClass());
//class java.lang.Object
}

4.finalize()方法

protected void finalize() throws Throwable {}

该方法用于释放资源。

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

关于垃圾回收,有三点需要记住:

1、对象可能不被垃圾回收。只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不 到释放。

2、垃圾回收并不等于“析构”。

【科普:析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完 毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟 了一片内存空间,delete会自动调用析构函数后释放内存)。】

3、垃圾回收只与内存有关。使用垃圾回收的唯一原因是为了回收程序不再使用的内存。

 finalize()的用途:

        无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。 这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储 空间。不过这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。

5.equals()方法

比较是否相同的函数:

                Object中的equals方法是直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参 obj所引用的对象是否是同一对象, 所谓同一对象就是指内存中同一块存储单元,如果this和obj指向的hi同一块内存对象,则返回true,如果 this和obj指向的不是同一块内存,则返回false。 注意:即便是内容完全相等的两块不同的内存对象,也返回false。 如果是同一块内存,则object中的equals方法返回true,如果是不同的内存,则返回false 如果希望不同内存但相同内容的两个对象equals时返回true,则我们需要重写父类的equal方法 String类已经重写了object中的equals方法(这样就是比较内容是否相等了)

源码如下:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
    String anotherString = (String)anObject;
    int n = value.length;
    if (n == anotherString.value.length) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = 0;
        while (n-- != 0) {
            if (v1[i] != v2[i])
                return false;
                i++;
        }
      return true;
    }
}
        return false;
}

6.hashCode()方法

        返回对象的hash码值。该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写 hashCode方法。这个方法在一些具有哈希功能的Collection中用到。 一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash Code() == obj2.hashCode(),但是 hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。

7.wait()方法

        源码如下

public final void wait() throws InterruptedException {
wait(0);
}
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException
{
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}

public final native void notify();
public final native void notifyAll();

wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。 wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔, 如果在规定时间内没有获得锁就返回。 调用该方法后当前线程进入睡眠状态,直到以下事件发生。

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

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

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

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

8.notify()方法

notify()唤醒对象上等待的某个线程

notifyall()唤醒对象上等待的全部线程

其他方法:

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之间的一个随机数

Random():创建一个新的随机数生成器。

Random(long seed):使用单个 long 种子创建一个新的随机数生成器。 你在创建一个Random对象的时候可以给定任意一个合法的种子数,种子数只是随机算法的起源数字, 和生成的随机数的区间没有任何关系。

代码如下:

public static void main(String[] args) {
Random rand =new Random();
int i=rand.nextInt(100);
System.out.println(i);
}

public static void main(String[] args) {
Random ran1 = new Random(25);
System.out.println("使用种子为25的Random对象生成[0,100)内随机整数序列: ");
for (int i = 0; i < 10; i++) {
System.out.print(ran1.nextInt(100) + " ");
}
System.out.println();
}

【方法摘要】

1. protected int next(int bits):生成下一个伪随机数。

2. boolean nextBoolean():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 boolean值。

3. void nextBytes(byte[] bytes):生成随机字节并将其置于用户提供的 byte 数组中。

4. double nextDouble():返回下一个伪随机数,它是取自此随机数生成器序列的、在0.0和1.0之间 均匀分布的 double值。

5. float nextFloat():返回下一个伪随机数,它是取自此随机数生成器序列的、在0.0和1.0之间均匀分 布float值。

6. double nextGaussian():返回下一个伪随机数,它是取自此随机数生成器序列的、呈高斯(“正 态”)分布的double值,其平均值是0.0标准差是1.0。

7. int nextInt():返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。

8. int nextInt(int n):返回一个伪随机数,它是取自此随机数生成器序列的、在(包括和指定值(不 包括)之间均匀分布的int值。

9. long nextLong():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 long 值。 10. void setSeed(long seed):使用单个 long 种子设置此随机数生成器的种子。

【例子】

1. 生成[0,1.0)区间的小数:double d1 = r.nextDouble();

2. 生成[0,5.0)区间的小数:double d2 = r.nextDouble() * 5;

3. 生成[1,2.5)区间的小数:double d3 = r.nextDouble() * 1.5 + 1;

4. 生成[0,10)区间的整数:int n2 = r.nextInt(10);

Date类

SimpleDateFormat类

格式化日期

public static void main(String args[]) {
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
System.out.println("当前时间为: " + ft.format(dNow));
}

String类

String 类代表字符串。Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。 字符串是 常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的, 所以可以共享。

 1. 常量池表(Constant_Pool table) Class文件中存储所有常量(包括字符串)的table。这是Class文件中的内容,还不是运行时的内容,不 要理解它是个池子,其实就是Class文件中的字节码指令。

1. 运行时常量池(Runtime Constant Pool)

JVM内存中方法区的一部分,这是运行时的内容。这部分内容(绝大部分)是随着JVM运行时候,从常 量池转化而来,每个Class对应一个运行时常量池。上一句中说绝大部分是因为:除了 Class中常量池内 容,还可能包括动态生成并加入这里的内容。

1. 字符串常量池(String Pool) 这部分也在方法区中,但与Runtime Constant Pool不是一个概念,String Pool是JVM实例全局共享 的,全局只有一个。JVM规范要求进入这里的String实例叫“被驻留的interned string”,各个JVM可以有 不同的实现,HotSpot是设置了一个哈希表StringTable来引用堆中的字符串实例,被引用就是被驻留。

StBuilder 和 StringBuffer

StringBuilder 是一个可变的字符序列。它继承于AbstractStringBuilder,实现了CharSequence接口。 StringBuffer 也是继承于AbstractStringBuilder的子类;但是,StringBuilder和StringBuffer不同,前者 是非线程安全的,后者是线程安全的。

常用方法有insert()

private static void testInsertAPIs(){
System.out.println("---------- testInsertAPIs -----------");
StringBuilder sbuilder = new StringBuilder();
// 在位置0处插入字符数组
sbuilder.insert(0, new char[]{'a', 'b', 'c', 'd', 'e'});
// 在位置0处插入字符数组。0表示字符数组起始位置,3表示长度
sbuilder.insert(0, new char[]{'A', 'B', 'C', 'D', 'E'}, 0, 3);
// 在位置0处插入float
sbuilder.insert(0, 1.414f);
// 在位置0处插入double
sbuilder.insert(0, 3.14159d);
// 在位置0处插入boolean
sbuilder.insert(0, true);
// 在位置0处插入char
sbuilder.insert(0, '\n');
// 在位置0处插入int
sbuilder.insert(0, 100);
// 在位置0处插入long
sbuilder.insert(0, 12345L);
// 在位置0处插入StringBuilder对象
sbuilder.insert(0, new StringBuilder("StringBuilder"));
// 在位置0处插入StringBuilder对象。6表示被在位置0处插入对象的起始位置(包括),13是
结束位置(不包括)
sbuilder.insert(0, new StringBuilder("STRINGBUILDER"), 6, 13);
// 在位置0处插入StringBuffer对象。
sbuilder.insert(0, new StringBuffer("StringBuffer"));
// 在位置0处插入StringBuffer对象。6表示被在位置0处插入对象的起始位置(包括),12是结
束位置(不包括)
sbuilder.insert(0, new StringBuffer("STRINGBUFFER"), 6, 12);
// 在位置0处插入String对象。
sbuilder.insert(0, "String");
// 在位置0处插入String对象。1表示被在位置0处插入对象的起始位置(包括),6是结束位置(不
包括)
sbuilder.insert(0, "0123456789", 1, 6);
sbuilder.insert(0, '\n');
// 在位置0处插入Object对象。此处以HashMap为例
HashMap map = new HashMap();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
sbuilder.insert(0, map);
System.out.printf("%s\n\n", sbuilder);}

 append

/**
* StringBuilder 的append()示例
*/
private static void testAppendAPIs() {
System.out.println("------------------- testAppendAPIs -----------------
--");
StringBuilder sbuilder = new StringBuilder();
// 追加字符数组
sbuilder.append(new char[]{'a','b','c','d','e'});
// 追加字符数组。0表示字符数组起始位置,3表示长度
sbuilder.append(new char[]{'A','B','C','D','E'}, 0, 3);
// 追加float
sbuilder.append(1.414f);
// 追加double
sbuilder.append(3.14159d);
// 追加boolean
sbuilder.append(true);
// 追加char
sbuilder.append('\n');
// 追加int
sbuilder.append(100);
// 追加long
sbuilder.append(12345L);
// 追加StringBuilder对象
sbuilder.append(new StringBuilder("StringBuilder"));
// 追加StringBuilder对象。6表示被追加对象的起始位置(包括),13是结束位置(不包括)
sbuilder.append(new StringBuilder("STRINGBUILDER"), 6, 13);
// 追加StringBuffer对象。
sbuilder.append(new StringBuffer("StringBuffer"));
// 追加StringBuffer对象。6表示被追加对象的起始位置(包括),12是结束位置(不包括)
sbuilder.append(new StringBuffer("STRINGBUFFER"), 6, 12);
// 追加String对象。
sbuilder.append("String");
// 追加String对象。1表示被追加对象的起始位置(包括),6是结束位置(不包括)
sbuilder.append("0123456789", 1, 6);
sbuilder.append('\n');
// 追加Object对象。此处以HashMap为例
HashMap map = new HashMap();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
sbuilder.append(map);
sbuilder.append('\n');
// 追加unicode编码
sbuilder.appendCodePoint(0x5b57); // 0x5b57是“字”的unicode编码
sbuilder.appendCodePoint(0x7b26); // 0x7b26是“符”的unicode编码
sbuilder.appendCodePoint(0x7f16); // 0x7f16是“编”的unicode编码
sbuilder.appendCodePoint(0x7801); // 0x7801是“码”的unicode编码
System.out.printf("%s\n\n", sbuilder);
}

replace

/**
* StringBuilder 的replace()示例
*/
private static void testReplaceAPIs() {
System.out.println("------------------- testReplaceAPIs-----------------
--");
StringBuilder sbuilder;
sbuilder = new StringBuilder("0123456789");
sbuilder.replace(0, 3, "ABCDE");
System.out.printf("sbuilder=%s\n", sbuilder);
sbuilder = new StringBuilder("0123456789");
sbuilder.reverse();
System.out.printf("sbuilder=%s\n", sbuilder);
sbuilder = new StringBuilder("0123456789");
sbuilder.setCharAt(0, 'M');
System.out.printf("sbuilder=%s\n", sbuilder);
System.out.println();}

delete

private static void testDeleteAPIs() {
System.out.println("------------------- testDeleteAPIs -----------------
--");
StringBuilder sbuilder = new StringBuilder("0123456789");
// 删除位置0的字符,剩余字符是“123456789”。
sbuilder.deleteCharAt(0);
// 删除位置3(包括)到位置6(不包括)之间的字符,剩余字符是“123789”。
sbuilder.delete(3,6);
// 获取sb中从位置1开始的字符串
String str1 = sbuilder.substring(1);
// 获取sb中从位置3(包括)到位置5(不包括)之间的字符串
String str2 = sbuilder.substring(3, 5);
// 获取sb中从位置3(包括)到位置5(不包括)之间的字符串,获取的对象是CharSequence对
象,此处转型为String
String str3 = (String)sbuilder.subSequence(3, 5);
System.out.printf("sbuilder=%s\nstr1=%s\nstr2=%s\nstr3=%s\n",
sbuilder, str1, str2, str3);}

index

/**
* StringBuilder 中index相关API演示
*/
private static void testIndexAPIs() {
System.out.println("-------------------------------- testIndexAPIs -----
---------------------------");
StringBuilder sbuilder = new StringBuilder("abcAbcABCabCaBcAbCaBCabc");
System.out.printf("sbuilder=%s\n", sbuilder);
// 1. 从前往后,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.indexOf(\"bc\")",
sbuilder.indexOf("bc"));
// 2. 从位置5开始,从前往后,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.indexOf(\"bc\", 5)",
sbuilder.indexOf("bc", 5));
// 3. 从后往前,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.lastIndexOf(\"bc\")",
sbuilder.lastIndexOf("bc"));
// 4. 从位置4开始,从后往前,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.lastIndexOf(\"bc\", 4)",
sbuilder.lastIndexOf("bc", 4));
System.out.println();}

 【String、StringBuffer、StringBuilder之间的区别】

首先需要说明的是: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 在大多数情况下三者在执行速度方面的比较:StringBuilder > StringBuffer > String 解释: String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以 经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中 无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。 而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而 不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对 象经常改变的情况下。 为什么是大多数情况呢?

在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接, 所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的: 你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本 一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个 String S1 = “This is only a” + “ simple” + “test”; 其实就是:String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象 的话,速度就没那么快了,譬如: String S2 = “This is only a”; String S3 = “ simple”; String S4 = “ test”; 大部分情况下StringBuilder的速度要大于StringBuffer: java.lang.StringBuilder一个可变的字符序列是5.0新增的。(大多数情况下就是我们是在单线程下进行 的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的)此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个 线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

对于三者使用的总结:

1)如果要操作少量的数据用 = String

2)单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

3)多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

File类

1. File的静态属性String separator存储了当前系统的路径分隔符。 2. 通过File对象可以访问文件的属性。

public class TestFile {
/**
* File文件类 1.代表文件 2.代表目录
*/
public static void main(String[] args) {
File f = new File("d:/src3/TestObject.java");
File f2 = new File("d:/src3");
File f3 = new File(f2, "TestFile.java");
File f4 = new File(f2, "TestFile666.java");
File f5 = new File("d:/src3/aa/bb/cc/dd");
//f5.mkdirs();
f5.delete();
try {
f4.createNewFile();
System.out.println("文件创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
if (f.isFile()) {
System.out.println("是一个文件!");
}
if (f2.isDirectory()) {
System.out.println("是一个目录!");
}
if (f3.isFile()) {
System.out.println("是一个文件奥");
}}
举报

相关推荐

0 条评论