Java JDK常用接口与String类

0、复习
(1)抽象类:普通类的超集,只是比普通类多了一些抽象方法而已。
        ①抽象类和抽象方法使用abstract修饰,抽象方法所在的类一定是抽象类
        ②抽象方法没有方法体,native方法也没有方法体
        ③抽象类也可以具备构造方法,实例方法等等,子类继承抽象类仍然遵从继承原则,先调用父类的构造方法再调用子类构造(即便父类是抽象类仍然满足此规则)
        ④抽象类仍然是单继承局限,子类必须满足is a原则,子类必须覆写抽象类的所有抽象方法。
(2)接口∶只有全局常量与抽象方法。interface定义接口
        ①仅在接口定义中 public、static、final、abstract统统都可以省略,接口中只保留最核心的方法与变量定义即可
        ②子类使用implements实现接口,接口的实现是多实现,一个类可以同时实现多个接口(接口的子类表示混合行为,不是is a原则)
        ③若子类既需要继承父类又需要实现接口,先使用extends继承一个父类,而后使用implements实现父接口
        ④接口不能使用extends来继承类,接口可以使用extends来继承多个父接口
(3)开发中接口的应用场景:表示一种规范/标准;或表示一种能力/行为
①JDK中的自定义类型表示大小关系比较的标准接口(java.lang.Comparable接口)

int compareTo(Object o)

        · return < 0:当前对象小于传入对象o
        · return = 0:当前对象等于传入对象o
        · return > 0:当前对象大于传入对象o
1、JDK另一个常用接口:java.lang.Cloneable :
(1)克隆

public interface cloneable{
}

· 空接口,这一类接口称为JDK中的标记接口

public class Animal implements Cloneable{
}

· 此时Animal的对象在JVM中运行时就具备了可以复制/拷贝的能力
(2)在Java中一个类要实现克隆(新建一个一样的对象)的能力,需要两步走:
        ①在类的定义之上实现Cloneable接口∶打标记,JVM只会将带Cloneable接口的子类赋予其可以拷贝的能力
        ②在类中覆写Object类的clone方法:具体实现的克隆方法
(3)Object:Object类是Java的万物之母,所有类默认都继承自Object父类,Object类中的所有方法所有类都具备
        ①Object类中的clone方法

protected native Object clone() throws CloneNotSupportedException;

· 具体的代码实现在JVM的Cpp代码中实现的,Java只是调用
        ②覆写object类的clone方法

//调用JVM的克隆方法即可,只是改变类型为当前类的类型即可
public Animal clone() throws CloneNotSupportedException { 
    //对象的拷贝交给JVM具体操作,相当Java的clone方法就是调用JVM的内部的clone方法而已
    return (Animal) super.clone(); 
}

③具体实现

Animal animal = new Animal("元宝",5); //被克隆对象
Animal animal1 = animal.clone(); //根据原对象animaL克隆一个完全一致的新对象

2、深浅拷贝
(1)浅拷贝:
        ①概念:当前类中若包含了其他类的引用,克隆后的新对象不会产生新的内部对象,浅拷贝只是将原对象中的所有属性值,复制一份儿而已
        ②举例

class Money { //Money类
    double sal = 10.5;
}

public class Person implements Cloneable{
    Money money = new Money(); //Person类中实例化了Money类
    int age;

    @override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}

· 浅拷贝只是将原对象中的所有属性值复制一份儿而已,若原对象中包含引用类型,拷贝对象只是复制引用的地址而已,并不会产生引用对象本身的新对象!
此时实例化per1,克隆per2,但他们的money指向的是同一个对象,只克隆了per,没克隆money
(2)深拷贝
        ①概念:∶产生的拷贝对象内部包含的其他类对象,也会复制一个新的对象产生。例如上面的深拷贝后也会产生新的money对象。
        ②以下两种方式可以实现深拷贝︰
        1.递归的clone方法调用(陈年老代码)
        利用上面的例子,修改clone方法

public Person clone() throws CloneNotSupportedException {
    Person per = (Person) super.cone();
    per.money = this.money.clone();
    return per;
}

        2.通过序列化的方式(现代所谓的json序列化与反序列化就在进行深浅拷贝)
        · 假设使用网络传输
                ①序列化操作:将任意对象转为字符串的操作
                ②通过网络传输字符串
                ③反序列化:根据json字符串构造对象
3、Object:Object类型除了是所有类的共同父类之外(可以接收所有的类的对象),还可以接受数组对象与接口对象

object obj1 = new Japanese("小泉",60,"日本"); //接收类的对象
IMessage message= new MessageImpl();
object gbi2.= message; //接收接口引用
object obj3 = new int[ 10]; //接收数组对象

· Object类型是引用数据类型的最高参数统一化,但是基本类型无法被Object所接受。为了让Object在Java中可以接一切数据值,产生了包装类。
4、包装类∶就是将基本数据类型值封装到类之中,这种类称之为包装类。
        ①范例:自己定义一个整型的包装类

public class MyInt {
    private int val;

    public MyInt(int val){
        this.val = val; //将整型数值保存到当前类之中
    }
    public int intVal() {
        return this.val; //取出当前保存的整型数值
    }
}


MyInt mi = new MyInt(10); //实例化
int val = mi.intVal(); //取出数值
Object obi = mi; //Object接收包装类对象

        ②JDK定义好的包装类

Integer i1 = new Integer(10);
int val = i1.intValue();
Object obi = i1;

        ③JDK中的包装类
        · Number类的直接子类
                - byte:Byte, short:Short, int:Integer, long:Long, float:Float, double:Double
        · Object的直接子类
                - char:Character, boolean:Boolean
        · Number类中的方法(取出当前数值转为对应的基本类型)
                .intValue()、.longValue()、.floatValue()、.doubleValue()、.byteValue()、.shortValue()
        · 将基本类型保存到对应的包装类中->装箱
        将包装类对象还原为具体基本类型->拆箱,在进行数学运算时,频繁将基本数值和包装类的对象进行转换,增加了代码的复杂度。从JDK1.5之后引入了自动拆装箱的机制。使用包装类对象就和使用基本类型一模一样,无须关注装箱与拆箱过程

Integer i1 = 10; //自动装箱
i1 += 20; //自动拆箱
Double b2 = 3.5; //自动装箱
b2 /= 2.1; //自动拆箱

        自动拆装箱机制是Java语法糖,只存在于源代码阶段。javac编译器搞定具体的装箱与拆箱操作
5、既然存在了自动拆装箱的机制,使用包装类就和使用基本类型一模一样。
阿里编码规约要求:
        在类中定义的属性,推荐使用包装类
        在方法中的局部变量,可以使用基本类型
        因为基本数据类型默认值0,引用数据类型默认值null,这样在数据库操作时更容易区分未初始化和0的区别
6、包装类比较问题
(1)对于引用数据类型,"==”只能比较两个引用的地址是否相同,不能比较内容是否一致!包装类对象也是如此

Integer i1 = 120;
Integer i2 = 120;
System.out.println(i1 == i2); //true
Integer i3 = 130;
Integer i4 = 130;
System.out.println(i3 == i4); //false

        · 整型包装类有缓存,默认缓存-128~127的数值,当第一次包装类对象的数值在这个区间内,产生新的包装类对象,当第二次以及之后又出现该数值,直接复用已有对象;所以第一个true
        · 在缓存区间之外的数值,不会复用已有对象每次自动装箱,都会产生新对象。所以第二个false
(2)切记!凡是引用类型的相等比较,千万别用"==",一定要使用.equals方法来进行对象的属性比较

Integer i1 = 120;
Integer i2 = 120;
System.out.println(i1.equals(i2)); //true
Integer i3 = 130;
Integer i4 = 130;
System.out.println(i3.equals(i4)); //true

        · JDK中常用的类,包装类,String类,统统覆写了equals方法进行属性值的比较,而非地址!
7、String
(1)关于字符串对象的产生
        ①直接通过字符串的常量来产生对象

String str1 = "hello world";

        ②通过构造方法产生字符串对象

String str2 = new String("hello world");

        ③使用字符数组来产生字符串对象

char[] value = {'a','b','c'};
String str3 = String.valueOf(value);

(2)字符串的对象相等比较,使用equals方法
        ①.equals()方法是按照两个不同的字符串对象内部的一个个字符进行比较,区分大小写的比较,碰到内容不相等的字符,返回false
        ②.equalsIgnoreCase()不区分大小写的字符串对象比较
(3)字符串对象的大小比较:String类也实现了Comparable接口,调用compareTo方法可以实现字符串大小的比较
        · compareTo方法的返回值:
        ①先按照字典序(ASCII编码)进行大小比较,若出现不相等字符,直接返回当前这两个字符的大小差值

String str1 = "abc";
String str2 = "AbC";
System.out.println(str1.compareTo(str2));

                - 返回值32,因为a和A差32
        ②两个字符串的长度不同,若前k个字符都是相等的(k表示最短长度),返回两个字符串的长度差值!

String str1 = "abcde";
String str2 = "abc";
System.out.println(str1.compareTo(str2));

                - 返回值2,因为abcde比abc长2
        ③当两个字符串对象完全相等,返回0
(4)字符串的转化
        ①其他类型转为字符串对象,调用valueOf方法

String s1 = String.valueOf(i: 123);
String s2 = String.valueOf(d: 123.4);
String s3 = String.valueOf(b: true);
String s4 = String.valueOf(new Student("铭哥",18));

        ②将字符串对象还原为数值,调用数值包装类提供的parseXXX方法

int i1 = Integer.parseInt(s1); //String -> int
double i2 = Double.parseDouble(s2); //String -> double

        · 特别注意,当字符串中包含了非数字内容,转换会出错!

8、字符串常用方法(所有高级语言中,字符串实际就是使用字符数组进行存储的)
(1)字符串查找
        ①char charAt(int index):返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常
        ②indexOf()
                · int indexOf(int ch) //返回ch第一次出现的位置,没有返回-1
                · int indexOf(int ch, int fromIndex) //从fromIndex位置开始找ch第一次出现的位置,没有返回-1
                · int indexOf(String str) //返回str第一次出现的位置,没有返回-1
                · int indexOf(String str, int fromIndex) //从fromIndex位置开始找str第一次出现的位置,没有返回-1
        ③lastIndexOf()
                · int lastIndexOf(int ch) //从后往前找,返回ch第一次出现的位置,没有返回-1
                · int lastIndexOf(int ch, int fromIndex) //从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1
                · int lastIndexOf(String str) //从后往前找,返回str第一次出现的位宣,没有返回-1
                · int lastIndexOf(String str, int fromIndex) //从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1
        ④boolean contains(字符/字符串) //查询当前字符串对象中是否包含指定内容,包含返回true,不包含返回false
(2)字符串替换:指定一个新的字符串子串替换已有的子串
        ①String replaceAll(String regex,String replacement) //替换所有的指定内容
        ②String replaceFirst(String regex, String replacement) //替换首个内容
(3)字符串的拆分:将一个完整的字符串对象,按照指定的分隔符拆分为字符串数组
        ①String[] split(String regex) //将字符串按照regex为分隔,全部拆分
        ②String[] split(String regex, int limit) //将字符串按照regex为分隔,最多拆分成limit个部分
                · 当limit < 拆分后的长度,部分拆分
                · 当limit >= 完全拆分后的长度,是完全拆分
        ③关于某些特殊分隔符的拆分问题:
                String[] strings = str.split(".");
        · 拆分时某些特殊的分隔符若在程序中有特殊含义,拆分时需要进行转义处理~
                String[] strings = str.split("\\.");
(4)字符串的截取方法
        ①String substring(int beginIndex) //从指定索引截取到结尾
        ②String substring(int beginIndex, int endIndex) //从开始位置截取到结束索引位置
                · JDK表示区间的函数,一般都是左闭右开,不包含结束索引的字符
(5)一组补充方法
        ①String trim() //去掉字符串中的左右全部空格,保留中间空格
        ②String toUpperCase() //字符串转大写
        ③string toLowerCase() //字符串转小写
9、常量池
(1)当字符串的对象采用直接赋值法创建时,JVM会维护一个字符串的常量池。当字符串对象第一次产生时,就会产生该字符串对象,置入常量池中。使用直接赋值法再次要产生该对象,若常量中已经包含了该值的对象,直接复用常量池中的对象,并不会产生新的字符串对象
如果是通过new产生字符串对象,就在堆上开辟新的空间

String str = "abc";
String str1 = "abc";
String str2 = new String("abc");
String str3 = new String("abc");

str == str1; // true
str == str2; // false
str2 == str3; // false

(2)intern()方法:调用该方法,会将当前的字符串对象尝试置入常量池中
        · 若常量池中已经包含当前字符串对象的内容,不会将当前对象置入常量池,返回常量池中原有的对象地址
        · 若常量池中没有包含当前字符串对象的内容,就将当前对象置入常量池中,返回的还是当前对象的地址
①情况1

char[] ch = new char[]{'a','b','c'};
String s1 = new String(ch); //堆上的字符串
String s2 = "abc"; //常量池上的字符串
System.out.println(s1==s2); //false

②情况2

char[] ch = new char[]{'a','b','c'};
String s1 = new String(ch); //堆上的字符串
s1.intern(); //将s1指向的字符串对象置入常量池中,且置入成功
String s2 = "abc"; //已有值为abc的对象,不产生新的,复用该对象
System.out.println(s1==s2); //true

③情况3

String s2 = "abc"; //第一次出现,JVM产生该对象置入常量池中
char[] ch = new char[]{'a','b','c'};
String s1 = new String(ch); //堆中新建对象
s1.intern(); //此时常量池中已经有了值为abc的对象,不会将当前s1的对象置入常量池中
System.out.println(s1==s2); //false

④情况4

String s2 = "abc"; //常量池中有了“abc”
char[] ch = new char[]{'a','b','c'};
String s1 = new String(ch); //堆中有了“abc”对象
s1 = s1.intern(); //将s1指向的字符串对象置入常量池中,置入失败,但返回常量池中“abc”的地址。s1引用变了
System.out.println(s1==s2); //true

· 所以平时相等比较要用.equals()方法就不会出错
10、字符串的不可变性:
(1)String对象一旦产生,字符串对象中保存的值不可改变。

string str = "hello";
str += "world";
str += "!!!";
System.out.println(str);

        · 上述代码中,一直改变的是字符串str的引用,不断在指向新的字符串对象。不断在常量池中产生了新的字符串对象,str这个引用一直在变,字符串常量池中一旦字符串对象产生,内容不变,这就是字符串对象的不可变性。
(2)原因
①源码

public final class String 
    implements java.io.Serializable,Comparable<String>,CharSequence {
        private final char value[]; //字符串对象的内容实际上在value数组中存储

        · value被final修饰,说明该引用一旦赋值,只能指向对应的字符数组对象(只有final不够,此时数组对象的内容还是可变的)
        · value被private修饰,且String类并没有对外部提供getter与setter方法,因此在String外部无法取得value数组对象,因此无法修改其内容!这才是不可变的本质所在!
②原因
· 那么多String提供的字符串修改方法,其实都是产生了新的字符串对象,并不是在原有基础上的修改。
· 以截取subString,replace为例,看似都更改了字符串的内容,本质全都产生了新的字符串对象!
③考点

//*******************************************************************
String str = "abc" ;
str = str.toUpperCase();

System.out.println(str == “ABC"); //false
//*******************************************************************
public static void change(String string, char[] data){
    string = "gbc"; //新局部变量string被赋值为"gbc"
    data[0]= ‘g'; //传入数组的首元素被改成g
}

string str = "abc";
char[] value = {'a','b','c'};
change(str, value); //str改变未生效(只是局部变量被改了),数组首元素的改变生效

system.out.println(str); //abc
system.out.println(Arrays.toString(value)); //gbc
//*******************************************************************

11、由于字符串的不可变性,因此当需要频繁的修改字符串内容时,我们就需要用到JDK提供的另外两个类。
(1)两个”SB“:StringBuffer 和 StringBuilder
        · 这两个类的使用完全一致,都是修改字符串内容时用到的两个类
                StringBuffer是线程安全的类,性能较差,一般用在多线程并发修改内容时
                StringBuilder是线程不安全的类,性能较高,能满足大部分的场景下使用
        · StringBuilder类和String类是完全独立的俩类型!!完全不是同一个类!! !
(2)将StringBuilder的对象转为字符串的对象:使用StringBuilder中的toString()方法
将字符串对象转为StringBuilder的对象
①通过构造方法

String str = "abc ";
StringBuilder sb = new StringBuilder(str);

②通过StringBuilder成员方法.append(str)拼接

StringBuilder sb1 = new StringBuilder();
sb1.append(str);

12、"SB"类的常用方法
(1)增
        ①StringBuffer append(String str) //在尾部添加内容
        ②StringBuffer insert(int offset, String str) //在指定索引位置插入新的内容。新内容插入之后成为索引为offset
(2)删
        ①StringBuffer deleteCharAt(int index) //删除指定索引的字符
        ②dStringBuffer delete(int start, int end) //删除索引为[start,end)的内容
(3)改
        ①void setCharAt(int index,char ch) //将index位置的字符设置为ch
        ②StringBuffer replace(int start,int end,String str) //将[start, end)位置的字符替换为str
(4)查
        ①char charAt(int index) //返回index位置上字符
        ②int indexOf(String str) //返回str第一次出现的位置
        ③int indexOf(String str, int fromIndex) //从fromIndex位置开始查找st第一次出现的位置
        ④int lastIndexOf(String str) //返回最后一次出现str的位置(从后往前找)
        ⑤int lastIndexOf(String str,int fromIndex) //从fromIndex位置开始找str最后一次出现的位置(从后往前找)
(5)转置
        ①.reverse() //将当前字符串逆序处理
(6)补充内容:当str使用"+"时,javac默认会将字符串的对象转为StringBuilder处理

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值