第十天 Object类(部分)和String类
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十天 Object类(部分)和String类相关的知识,希望对你有一定的参考价值。
Java的API
Java的API(API:Application(应用)Programming(程序)Interface(接口))
JavaAP就是JD中提供给我们使用的类,这些类将底层代码实现封装起来了.我们不需要关系这些类是如何实现的,只需要虚心如何使用这些类.
JKD安装目录下有个src.zip文件,这个文件解压后里面的内容就是所有java的类.可以参看对应的源码.
其次我们可以通过查找帮助文档的方式,来了解Java提供的API如何使用哪些类
Object类的概述
构造方法public Object()
Object类是Java语言的根类,即所有类的父类.他描述了所有的方法子类都可以使用.java中的每个类都是有他扩展而来的.如果没有明确的指出超类,onject就被认为是这个类的超类.
可以使用Object类型的变量引用任何类型的对象.
在Java中只有基本数据类型不是对象,所有的数组类型,不管是对象数组还是基本数组都扩展与Object
接口(Interface)并不继承于object.但是接口类型的父类引用也可拥有Object类的一般方法
转载https://blog.csdn.net/xidiancoder/article/details/78011148
引用自 《The Java Language Specification, Java SE 8 Edition》 中的第9章9.2节
If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throwsclause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface.
如果一个接口定义是最顶级的(没有 super interfaces),那么这个接口会自动声明一个 abstract member method 结构体来代表所有来自 Object 类(一切类的superclass)中的public方法(包括这些方法的签名、返回类型以及抛出的异常)
再换种说法——意思是接口隐含定义了一套与Object类中的方法签名完全相同的方法,所以,我们在程序中调用接口的那些与Object中具有相同签名的方法时,编译器不会报错!
equals
Equals方法,用于比较两个对象是否相同,他其实就是使用两个对象的内存地址在比较.Object类中的equsls方法内部使用的就是==比较运算符.
public boolean equals(Object obj) {
return (this == obj);
}
然而在大多数时候我比较两个类是否相同会根据对象中的属性值进行比较,也就是我们要经常重写equals方法,实现自己的比较方式.
/*
描述人这个类,并定义功能根据年龄判断是否是同龄人
由于要根据指定类的属性进行比较,这时只要覆盖Object中的equals方法
在方法体中根据类的属性值进行比较
*/
class Person extends Object{
int age ;
//复写父类的equals方法,实现自己的比较方式
public boolean equals(Object obj) {
//判断当前调用equals方法的对象和传递进来的对象是否是同一个
if(this == obj){
return true;
}
//判断传递进来的对象是否是Person类型
if(!(obj instanceof Person)){
return false;
}
//将obj向下转型为Perosn引用,访问其属性
Person p = (Person)obj;
return this.age == p.age;
}
}
==和equals的区别
==是一个比较运算符,既可以比较基本数据类型,也可以比较引用数据类型,基本数据类型就是比值,引用数据类型比较的是地址值
equals是一个比较运算符,只能比较引用数据类型,所有的对象都会继承Object类中的方法,如果没有重写Object类中的equals方法equals方法和==号比较引用数据类型没有区别,重写后的equals方法比较的是对象的属性.
在子类中定义equals方法时
首先调用超类中的equals,如果检测失败,对象就不可能相等,如果超类都相等了,就需要调用子类中的实例域
Java语言规范要求equals方法具有以下的特性:
1. 自反性 对于任意非空引用x x.equals(x) 应该返回true
2. 对称性 对于任意引用x和y 当且仅当y.equals(x),x.equals(y)也应该返回true.
3. 传递性 对于任意引用x,y,z 如果x.equals(y)返回true,y.equals(z)返回true,x.equals(z)也应该返回true
4. 一致性 如果x,y的引用的对象没有发生任何变化,反复调用x.equals(y)应该返回相同的结果.
5. 对与于任意非空引用x x.equals(null)都返回false
编写一个完美equals方法的建议
显式参数命名为otherObject,稍后需要将他转换为另一个叫做other的变量
检测this和otherObject是否引用同一个对象
if(this==otherObject)return true;
检测this和otherObject是否属于同一个类.如果equals的语义在每个子类中有所改变就使用getClass检测
if (getClass()!=otherObject.getClass))return false;
如果所有的子类都拥有同一的语义,就使用intanceof检测:
If(!(otherObject instanceof ClassName)) return false;
将otherObject转换为对应的类的类型变量
ClassName other = (ClassName) otherObject;
现在开始丢所有有需要比较的属性进行比较; ,使用==比较基本类型,使用equals比较引用类型.
如果在子类中重写定义equals,就要在其中包含调用super.equals(other)
在java核心技术上看到了这么一大堆,就语言规范看懂了,剩下那个完美编写,先放着把慢慢理解
toString方法
toString方法返回该对象的字符串表示,其实该字符串内容就是对象;类型[email protected]+内存地址值,在开发中,经常要按照对象的属性得到相应的字符串表现形式,
Object类中toString的核心代码
getClass().getName() + "@" + Integer.toHexString(hashCode())
例如
class Person extends Object{
int age ;
//根据Person类的属性重写toString方法
public String toString() {
return "Person [age=" + age + "]";
}
}
l 只要对象与一个字符串通过”+”连接起来,java编译就会自动地调用toString方法,以便获得这个对象的字符串描述
l 在调用x.toString()的地方可以用””+x代替,这个语句将一个空串与x的字符串表示相连接,就算x是基本类型,这条语句也能照样能够执行
l 调用System.out.println(x);println方法会自动调用x.toString(),并打印输出得到的字符串
l 而数组继承了Object的toString方法,想要打印数组应该调用Arrays.toString.多维数组使用Arrays.deeptoString.
String类
Java中字符串属于对象,Java通过String来创建和操作对象
Java中的所有字符串字面值”abc”都是作为此类实现的
字符串是常量,创建之后不能更改,但引用变量中记录的地址值是可以改变的.
源码分析
String类底层采用的是字符串数据:
private final char value[]
Private修饰说明value只能在String类内部使用,而且又没有get方法,所以外部无法获取value数组的值,就无法改变数组元素的值
Final修饰说明value是常量,一旦创建,就不能改变.value一旦被初始化成某个数组,就将永远指向这个数组,不能再指像其他数组了
String类创建方式和比较
String s = “abc”;//在内存中只有一个对象,这个对象在字符串常量池中
String s1=new String(“abc”);//内存中有两个对象,一个new在堆内存中,一个在字符串常量池中s1指向了那个堆内存中new出来的对象,new出来的对象指向了”abc”
Java中将String类定义为final(不可改变的),JVM中字符串一般保存在字符串常量池中,这个字符串常量池在jdk 6.0以前是位于常量池中,位于永久代,而在JDK 7.0中,JVM将其从永久代拿出来放置于堆中。
(永久代有是啥 感觉真的要去看看看java虚拟机或许这根本就不是我这个阶段所应该了解的东西吧)
String s2 = "abc";
String s3 = "abc";
String s4 = new String("abc");
System.out.println(s2==s3);//true
System.out.println(s3==s4);//false
System.out.println(s3.equals(s4));//true,
//因为String重写了equals方法,建立了字符串自己的判断相同的依据(通过字符串对象中的字符来判断
因为String太过常用,JAVA类库的设计者在实现时做了个小小的变化,即采用了享元模式,每当生成一个新内容的字符串时,他们都被添加到一个共享池中,当第二次再次生成同样内容的字符串实例时,就共享此对象,而不是创建一个新对象,但是这样的做法仅仅适合于通过=符号进行的初始化。
使用String s4 = new String("abc");这种方法创建对象时,jvm是不会主动把该对象放到共享池里面的,除非程序调用 String的intern方法。
String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;
(这啥intern()方法有是啥啊,什么时候应该会啊懵比)
Java中的String被设计成不可变的,出于以下几点考虑:
1. 字符串常量池的需要。字符串常量池的诞生是为了提升效率和减少内存分配。可以说我们编程有百分之八十的时间在处理字符串,而处理的字符串中有很大概率会出现重复的情况。正因为String的不可变性,常量池很容易被管理和优化。
2. 安全性考虑。正因为使用字符串的场景如此之多,所以设计成不可变可以有效的防止字符串被有意或者无意的篡改。从java源码中String的设计中我们不难发现,该类被final修饰,同时所有的属性都被final修饰,在源码中也未暴露任何成员变量的修改方法。(当然如果我们想,通过反射或者Unsafe直接操作内存的手段也可以实现对所谓不可变String的修改)。
3. 作为HashMap、HashTable等hash型数据key的必要。因为不可变的设计,jvm底层很容易在缓存String对象的时候缓存其hashcode,这样在执行效率上会大大提升。
/*
* String类构造方法
* String类的构造方法,重载形式
*
*/
public class StringDemo3 {
public static void main(String[] args) {
function_1();
}
/*
* String(char[] value) 传递字符数组
* 将字符数组,转成字符串, 字符数组的参数,不查询编码表
*
* String(char[] value, int offset, int count) 传递字符数组
* 将字符数组的一部分转成字符串
* offset 数组开始索引
* count 个数
*/
public static void function_1(){
char[] ch = {'a','b','c','d','e','f'};
//调用String构造方法,传递字符数组
String s = new String(ch);
System.out.println(s);
String s1 = new String(ch,1,4);
System.out.println(s1);
}
/*
* 定义方法,String类的构造方法
* String(byte[] bytes) 传递字节数组
* 字节数组转成字符串
* 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
* 平台 : 机器操作系统
* 默认字符集: 操作系统中的默认编码表, 默认编码表GBK
* 将字节数组中的每个字节,查询了编码表,得到的结果
* 字节是负数,汉字的字节编码就是负数, 默认编码表 ,一个汉字采用2个字节表示
*
* String(byte[] bytes, int offset, int length) 传递字节数组
* 字节数组的一部分转成字符串
* offset 数组的起始的索引
* length 个数,转几个 , 不是结束的索引
*/
public static void function(){
byte[] bytes = {97,98,99,100};
//调用String类的构造方法,传递字节数组
String s = new String(bytes);
System.out.println(s);
byte[] bytes1 ={65,66,67,68,69};
//调用String构造方法,传递数组,传递2个int值
String s1 = new String(bytes1,1,3);
System.out.println(s1);
}
}
/*
* String类的查找功能
*/
public class StringDemo4 {
public static void main(String[] args) {
function_9();
}
/*
* boolean equals(Object obj)
* 方法传递字符串,判断字符串中的字符是否完全相同,如果完全相同返回true
*
* boolean equalsIgnoreCase(String s)
* 传递字符串,判断字符串中的字符是否相同,忽略大小写
*/
public static void function_9(){
String str1 = "Abc";
String str2 = "abc";
//分别调用equals和equalsIgnoreCase
boolean b1 = str1.equals(str2);
boolean b2 = str1.equalsIgnoreCase(str2);
System.out.println(b1);
System.out.println(b2);
}
/*
* char[] toCharArray() 将字符串转成字符数组
* 功能和构造方法相反
*/
public static void function_8(){
String str = "itcast";
//调用String类的方法toCharArray()
char[] ch = str.toCharArray();
for(int i = 0 ; i < ch.length ; i++){
System.out.println(ch[i]);
}
}
/*
* byte[] getBytes() 将字符串转成字节数组
* 此功能和String构造方法相反
* byte数组相关的功能,查询编码表
*/
public static void function_7(){
String str = "abc";
//调用String类方法getBytes字符串转成字节数组
byte[] bytes = str.getBytes();
for(int i = 0 ; i < bytes.length ; i++){
System.out.println(bytes[i]);
}
}
/*
* int indexOf(char ch)
* 查找一个字符,在字符串中第一次出现的索引
* 被查找的字符不存在,返回-1
*/
public static void function_6(){
String str = "itcast.cn";
//调用String类的方法indexOf
int index = str.indexOf('x');
System.out.println(index);
}
/*
* boolean contains (String s)
* 判断一个字符串中,是否包含另一个字符串
*/
public static void function_5(){
String str = "itcast.cn";
//调用String类的方法contains
boolean b =str.contains("ac");
System.out.println(b);
}
/*
* boolean endsWith(String prefix)
* 判断一个字符串是不是另一个字符串的后缀,结尾
* Demo.java
* .java
*/
public static void function_4(){
String str = "Demo.java";
//调用String类方法endsWith
boolean b = str.endsWith(".java");
System.out.println(b);
}
/*
* boolean startsWith(String prefix)
* 判断一个字符串是不是另一个字符串的前缀,开头
* howareyou
* hOw
*/
public static void function_3(){
String str = "howareyou";
//调用String类的方法startsWith
boolean b = str.startsWith("hOw");
System.out.println(b);
}
/*
* String substring(int beginIndex,int endIndex) 获取字符串的一部分
* 返回新的字符串
* 包含头,不包含尾巴
*
* String substring(int beginIndex)获取字符串的一部分
* 包含头,后面的字符全要
*/
public static void function_2(){
String str = "howareyou";
//调用String类方法substring获取字符串一部分
str= str.substring(1, 5);
System.out.println(str);
String str2 = "HelloWorld";
str2 = str2.substring(1);
System.out.println(str2);
}
/*
* int length() 返回字符串的长度
* 包含多少个字符
*/
public static void function(){
String str = "cfxdf#$REFewfrt54GT";
//调用String类方法length,获取字符串长度
int length = str.length();
System.out.println(length);
}
}
以上是关于第十天 Object类(部分)和String类的主要内容,如果未能解决你的问题,请参考以下文章