您的当前位置:首页正文

03_Java_Class

来源:个人技术集锦
wangzg@tarena.com.cn

Java

中重要类

一、Object类

类Object是类层次结构的根类。每个类都使用Object作为超类。所有对象(包括数组)都实现这个类的方法。Object类的方法

1、clone()克隆,拷贝

一个对象参与序列化过程,那么对象流会记录该对象的状态,当再次序列化时,会重复序列化前面记录的对象初始状态,我们可以用对象克隆技术来解决这个问题(注意:直接用等号赋值只是把对象的地址复制一份,而用clone方法是把对象复制一份)

//Object类中提供的clone方法是protected修饰的,故我们要覆盖改方法publicclassStudentimplementsjava.lang.Cloneable{privateStringname;privateintage;

publicStudent(Stringname,intage){this.name=name;this.age=age;}

//set和get方法

publicvoidclone()throwsCloneNotSupportedException{super.clone();}}

publicclassTest{

publicstaticvoidmain(String[]args)throwsCloneNotsupportedException{

Students1=newStudent(\"zhanglimeng\//直接用等号赋值,会发现指向的是同一个对象,所以s2的age变了之后,s1的age也发生了改变。Students2=s1;s2.setAge(20);Students3=null;

System.out.println(s1.getAge());

//注意在这里是不能直接调用object的clone方法的

//s3=s1.clone();会报错,因为clone是protected修饰的//在Student类中添加了clone方法时候可以调用了s3=(Student)s1.clone();

//需要让Student类实现java.lang.Cloneable接口,要注意的是cloneable接口是标记接口,它只是标记该类对象可以被克隆,标记接口中没有方法。否则会抛出CloneNotSupportedException异常s3.setAge(40);

//注意观察下一句s1的age有没有发生变化System.out.println(s1.getAge());

wangzg@tarena.com.cn

}}

什么是浅克隆?什么是深克隆?

1)前者是把对象的内存空间中的数据直接复制一份,不管其中的数据类型是引用类型还是基本类型,这样会导致两个对象可能有指向同一个对象的属性。这样新对象和原对象还是有关系的。

2)后者是:在复制对象的时候,不是把所有属性的值原封不动的拷贝过来,而是在拷贝的时候分类,如果要拷贝的属性是引用,就会把引用指向的对象重新创建一份,然后用一个新的引用指向这个新对象,把这个新对象的引用放在复制的对象中;如果要拷贝的属性是基本类型,直接复制就可以了。3)疑问:为什么String类型的属性在浅克隆的时候也是互不影响的?关键是String这个类型决定的,一旦声明并且复制了一个String类型的对象之后,那么这个对象的值永远都不会改变,比如Strings=\"张三\";如果你重新给s赋了值之后,比如s=\"lisi\指向的对象的值改成了内容lisi,而是重新创建了一个内容为lisi的对象,把这个对象的地址给了引用。2、equals(Objectobj)

用来判断对象的值是否相等。前提是覆盖了equals方法。Object类中的equals方法判断的依然是地址注意:String类已经覆盖了equals方法,所以能用equals来判断String对象的值是否相等。

下面是覆盖equals方法的标准流程:publicbooleanequals(Objectobj){//第一步:现判断两个对象地址是否相等if(this==obj)returntrue;

//第二步:如果参数是null的话直接返回false;if(obj==null)returnfalse;

//第三步:如果两个对象不是同一个类型直接返回falseif(objinstanceofStudent){Students=(Student)obj;

if(s.name.equals(this.name)&&s.age==this.age){//比较规则由我们自己制定

returntrue;}}

returnfalse;}

覆盖equals的原则:

自反性(自己=自己)、2.对称性(y=x则x=y)、

3.一致性(多次调用,结果一致)、4.传递性(A=B,B=C则A=C)。

非空原则:t1.equals(Null)返回False;(如果t1不等于空)

wangzg@tarena.com.cn

注意:

==和equals的区别

1.基本类型用==去比较比的是值是否相等.

2.如果是对象用==比是两个引用中的地址值是否相等3.equals比较两个对象内容是否相等3、finalize()

当java的垃圾回收器回收对象的时候,会自动调用这个方法,所以这个方法中一般写资源回收的代码,所以这个方法和构造方法是一对。是由垃圾回收器自动调用的,不是程序员自己调用的。垃圾回收器是否启动不是程序员说了算。

也是需要在子类中去覆盖,因为每个类释放什么资源都不一样。4、toString()

给出这个对象的字符串的表示方式

当一个对象被打印的时候,其实会去调用这个对象的toString方法,即打印的是toString方法的返回值。

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

getClass().getName()+'@'+Integer.toHexString(hashCode())5、hashCode()

返回该对象的哈希码值。hashCode的常规协定是:在Java应用程序执行期间,在对同一对象多次调用hashCode方法时,必须一致地返回相同的整数,前提是将对象进行equals比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

如果根据equals(Object)方法,两个对象是相等的,那么对这两个对象中的每个对象调用hashCode方法都必须生成相同的整数结果。

如果根据equals方法,两个对象不相等,那么对这两个对象中的任一对象上调用hashCode方法不要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。实际上,由Object类定义的hashCode方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是JavaTM编程语言不需要这种实现技巧。)

总结:在Object中介绍的clone、equals、finalize、toString方法都是需要程序员自己去覆盖的,注意什么时候去覆盖。二、String类

概念(必须掌握的)

(1)String:是一组不可改变的unicode的字符序列。

理解不变——不管对String对象作任何操作,原来的String是不可改变的。一个String的值在一次虚拟机里是不会改变的。

Stringname=“zhanglimeng”这里的String值“zhanglimeng”是共享的,它的值在String常量池里。池:堆里的一片独立空间,用一个存储区域来存放一些公用资源以减少存储空间

wangzg@tarena.com.cn

的开销。目的是拿空间换时间,让运算效率更高。

Stringname1=newString(“zhanglimeng”)这里的值是独立的,它的值在堆里分配空间。

所以name==name1的结果是false;

name.equals(name1)的结果是true;//因为String的实现中重写了equals()方法。

Strings1=newString(\"abc\");Strings2=newString(\"abc\");Strings3=\"abc\";Strings4=\"abc\";Strings5=s3+\"d\";Strings6=s4+\"d\";Strings7=s1+\"d\";Strings8=s2+\"d\";Strings9=\"abcd\";Strings10=\"abc\"+\"d\";结果:

System.out.println(s1==s2);f

System.out.println(s1.equals(s2));tSystem.out.println(s3==s4);t

System.out.println(s1.equals(s4));tSystem.out.println(s5==s6);fSystem.out.println(s7==s8);fSystem.out.println(s9==s10);tString里的常用方法(重点掌握)(1)publiccharcharAt(intindex)

返回指定索引处的char值。索引范围为从0到length()-1。

序列的第一个char值在索引0处,第二个在索引1处,依此类推,这类似于数组索引。

(2)indexOf(Stringstr)

返回指定字符在此字符串中第一次出现处的索引,如果找不到就返回-1。例如:

\"abcd\".indexOf(\"a\")结果是0;\"abcd\".indexOf(\"e\")结果是-1;(3)matches(Stringregex)

判断此字符串是否匹配给定的正则表达式正则表达式:预定义字符.代表任意字符\\d数字[0-9]\\D非数字[^0-9]

\\s空白字符[\\\n\\f\\r]\\S非空白字符[^\\s]

wangzg@tarena.com.cn

\\w单词字符[a-zA-Z_0-9]\\W非单词字符[^\\w]^行的开头$行的结尾

\\表示转义字符。

[]表示在其中任选择一个。

?表示出现0~1次可用于选择((.cn)|(.com))?//|代表或的关系

+表示出现1~n次比较常用例:[0-9]+*表示出现0~n次例如:[0-9]*{n}表示必须出现n个{n,}表示出现的个数>n

{n,m}表示n<=x<=m表示n到m之间。

()括号里面的作为一个整体,提升优先级。常用正则:

^[\\w-]+[@][\\w_-]+(\\com|\\.net)$email地址^1[358]\\d{9}$国内手机

^(\\d{3}-|\\d{4}-)?(\\d{8}|\\d{7})$国内固定电话^[1-9]\\\\d{4,9}$腾讯QQ号^[\一-\龥]$中文字符

^\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}$IP地址

匹配帐号是否合法(字母开头,允许6-16位,允许字母数字下划线):^[a-zA-Z][\\w]{5,15}$

^(\\d{2}|\\d{4})-((0([1-9]{1}))|(1[0-2]))-(([0-2]([1-9]{1}))|(3[0|1]))$年-月-日

\"^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5]).(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$\"IP地址(绝对)

(4)split(Stringregex)

根据给定的正则表达式的匹配来拆分此字符串。

Stringmessage=\"张三,男,25;李四,女,23;王老五,男,30\";//将上面字符串的信息封装成几个Pseron对象存入数组String[]strs=message.split(\";\");Person[]p=newPerson[strs.length];for(inti=0;i(5)publicbyte[]getBytes(StringcharsetName)

使用指定的字符集将此String解码为字节序列,并将结果存储到一个新的字节数组中。

wangzg@tarena.com.cn

常用于转换编码:

如:newString(src.getBytes(oldCharsetName),newCharsetName);(6)trim()

返回去除首尾的空白后的字符串

常用在从用户网页的输入框获得的字符串后,去除首尾的空白(7)substring()

(a)Stringsubstring(intbeignIndex)子串为指定下标到字符串结尾\"abcdefg\".substring(3);

(b)Stringsubstring(intbeignIndex,intendIndex)子串为指定开始下标到结束下标,不包括结束下标\"abcdefg\".substring(3,5);(8)compareTo

intcompareTo(StringanthorString)按字典顺序比较两个字符串

intcompareToIgnoreCase(StringanthorString)不考虑大小写,按字典顺序比较两个字符串(9)length()

返回字符串的长度

三、StringBuffer&StringBuilder

当对String进行频繁的修改时,应该用StringBuffer或StringBuilder代替String

StringBuffer是线程安全的(允许多个人同时操作),效率较低StringBuilder是线程不安全的(多个人操作时可能出错),效率高(1)Stringstr=\"1\"+\"2\"+\"3\"+\"4\";在生成str的过程中,会在串池中产生多余对象\"12\而我们真正需要的只有最后的对象\"1234\",不管在时间上还是在内存上都会造成相当大的浪费,所以应该使用StringBuffer(线程安全的)或者StringBuilder(线程不安全的)。解决方案:Strings=\"\";

StringBufferbuffer=newStringBuffer(\"1\");buffer.append(\"2\");buffer.append(\"3\");buffer.append(\"4\");s=buffer.toString();

(2)StringBuffer和StringBuilder没有重写equals()方法;例子:

StringBuffersb1=newStringBuffer(\"abc\");StringBuffersb2=newStringBuffer(\"abc\");System.out.println(sb1==sb2);

System.out.println(sb2.equals(sb2));//equals没有重写。System.out.println(\"\");

System.out.println(sb1.capacity()+\":\"+sb1.length());//19:3结果都是false。

wangzg@tarena.com.cn

(3)reverse()方法可以使字符串反转(4)append(?)

将指定参数的字符串追加到此字符序列(5)capacity()返回当前容量

(6)length()返回长度(字符数)四、Math类

Math类是final类型的,因此不能有子类;

Math类的构造是private类型的,因此不能实例化;提供了诸多用于数学计算的静态方法:返回类型方法名及描述参数类型

Int/long/float/doubleabs()返回绝对值int/long/float/doubleInt/longfloat/doublemax()返回两者较大者int/long/float/oubleInt/long/float/doublemin()返回两者较小者int/long/float/doubledoublepow(x,y)返回x的y词幂doubledoublerandom()返回[0-1)之间随机数long/intround()四舍五入double/float五、BigDecimal类

如果实际应用程序允许存在适当误差,那么可以使用float或double类型;如果需要进行精确运算,则应该使用java.math.BigDecimal类构造方法

BigDecimal(doubleval)

将double转换为BigDecimal,后者是double的二进制浮点值准确

的十进制表示形式。(注:并不能解决误差问题,需将double转为String构造)

BigDecimal(intval)

将int转换为BigDecimal。BigDecimal(longval)

将long转换为BigDecimal。BigDecimal(Stringval)

将BigDecimal的字符串表示形式转换为BigDecimal。该类中的方法:

add(BigDecimalb):进行精确的加法运算;

subtract(BigDecimalb):进行精确的减法运算;multiply(BigDecimalb):进行精确的乘法运算;

divide(BigDecimalb,intscale,RoundingModemore):进行除法运算;

•参数scale,指定需要精确到小数点以后几位;•参数mode,指定小数部分的舍入模式

–BigDecimal.ROUND_HALF_UP,表示四舍五入;doubleValue()将此BigDecimal转换为double。

equals(Objectx)比较此BigDecimal与指定的Object的相等性floatValue()将此BigDecimal转换为float。intValue()将此BigDecimal转换为int。

wangzg@tarena.com.cn

longValue()将此BigDecimal转换为long。六、日期类

java.util.Date:包装了一个long类型的数据;

表示GMT(格林尼治标准时间)的1970年1月1日00:00:00到当前所相差的毫秒数;

构造:Date()返回当前系统时间

方法:longgetTime()返回自1970年1月1日00:00:00GMT以来此Date对象表示的毫秒数。

其余构造与方法均已过时不推荐使用

java.util.Calendar抽象类其子类GregorianCalendar属性

HOUR_OF_DAY指示一天中的小时。DAY_OF_MONTH指示一个月中的某天。MONTH指示月份。YEAR指示年字。方法

IntcompareTo(CalendaranotherCalendar)

比较两个Calendar对象表示的时间值(从历元至现在的毫秒偏移量)。CalendargetInstance()

使用默认时区和语言环境获得一个日历。DategetTime()

返回一个表示此Calendar时间值(从历元至现在的毫秒偏移量)的Date对象。setTime(Datedate)

使用给定的Date设置此Calendar的时间。LonggetTimeInMillis()

返回此Calendar的时间值,以毫秒为单位。roll(intfield,booleanup)

在给定的时间字段上添加或减去(上/下)单个时间单元,不更改更大的字段。roll(intfield,intamount)

向指定日历字段添加指定(有符号的)时间量,不更改更大的字段java.text.DateFormat

DateFormat是日期/时间格式化子类的抽象类

SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类。

SimpleDateFormat(Stringpattern)用给定的模式和默认语言环境的日期格式符号构造

SimpleDateFormat。yyyy-MM-ddHH:mm:ss年-月-日时:分:秒

Stringformat(Datedate)将一个Date格式化为日期/时间字符串。

Dateparse(Stringsource)从给定字符串的开始解析文本,以生成一个日期。七、类型封装类

java为每一个简单数据类型提供了一个封装类,使每个简单数据类型可以被Object来装载。除了int(Integer)和char(Character),其余类型首字

wangzg@tarena.com.cn

母大写即成封装类类型名。

封装类、字符串、基本类型互相转换

int----------------------newInteger(x)---------------->IntegerString-----------------Integer.valueOf(s)---------------->IntegerInteger-----------------x.toString()--------------------->Stringint----------------------100+””------------------------->StringString------------------Integer.parseInt(s)--------------->intInteger-----------------Integer.intValue()--------------->int使用封装类的好处:

1、能把String转成封装类对应的基本类型

2、为基本类型记录一些信息,如:最大值,最小值3、实现了基本类型的对象化处理。自动封箱AutoBoxing/自动解封自动封箱和自动拆箱,它实现了简单类型和封装类型的相互转化时,实现了自动转化。

byteb-128~127

Byteb在以上数量的基础上多一个null简单类型和封装类型之间的差别

封装类可以等于null,避免数字得0时的二义性。Integeri=null;

intii=i;//会抛出NullException异常。相当于intii=i.intValue();Integeri=1;//相当于Integeri=newInteger(1);i++;//i=newInteger(i.intValue()+1);在基本数据类型和封装类之间的自动转换5.0之前

Integeri=newInteger(4);intii=i.intValue();注:抽象类Number是BigDecimal、BigInteger、Byte、Double、Float、Integer、Long和Short类的父类。

5.0之后

Integeri=4;

publicvoidm(inti){......}publicvoidm(Integeri){......}以上两个函数也叫方法重载

自动封箱解箱只在必要的时候才进行。能不封箱找到匹配的就不封箱。2、静态导入StaticImport

使用类中静态方法时不用写类名

System.out.println(Math.round(PI));可以用以下代码实现:

importstaticjava.lang.System.*;//注意,要写\"类名.*\"importstaticjava.lang.Math.*;out.println(round(PI));

wangzg@tarena.com.cn

注意:静态引入的方法不能重名3、for-each

统一了遍历数组和遍历集合的方式

for(Objecto:list){//Objecto表示每个元素的类型,list表示要遍历的数组或集合的名字

System.out.println(o);//打印集合或数组中的每个元素}

4、可变长参数

处理方法重载中,参数类型相同,个数不同的情况publicvoidm(int...is){.....}int...is相当于一个int[]is

编译器会把给定的参数封装到一个数组中,再传给方法

在一个方法中只能有一个可变长参数,而且,必须放在最后一个参数的位置内部类

内部类也就是定义在类内部的类。是编译时语法。内部类的分类:

成员内部类MenberInnerClass静态内部类、StaticInnerClass局部内部类、LocalInnerClass

匿名内部类AnonymousInnerClass(重点必须掌握)

(注意:前三种内部类与变量类似,所以可以对照参考变量)1、成员内部类

四个访问权限修饰符都可以修饰成员内部类。

内部类和外部类在编译时是不同的两个类,内部类对外部类没有任何依赖。内部类是一种编译时语法,在编译时生成的各自的字节码文件(Outer.class和Outer$Inner.class),内部类和外部类没有关系。内部类中可以访问外部类的私有成员。

作为外部类的一个成员存在,与外部类的属性、方法并列。内部类和外部类的实例变量可以共存。在内部类中访问实例变量:this.属性

在内部类访问外部类的实例变量:外部类名.this.属性。成员内部类的特点:

(1)内部类作为外部类的成员,可以访问外部类的私有成员或属性。(即使将外部类声明为private,但是对于处于其内部的内部类还是可见的。)

(2)用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限。

注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。(3)成员内部类不能含有静态成员。建立内部类对象时应注意:

在外部类的内部可以直接使用inners=newinner();(因为外部类知道inner是

wangzg@tarena.com.cn

哪个类,所以可以生成对象。)publicclassMemberInner{privateinti=1;

privatestaticinti2=0;publicclassTest{inti=2;

publicvoidtest(){

System.out.println(this.i);//内部类属性i

System.out.println(MemberInner.this.i);//外部类属性iSystem.out.println(i2);go();}}

publicvoidgo(){

System.out.println(\"go\");}

publicstaticvoidmain(String[]args){MemberInnermi=newMemberInner();Testtest=mi.newTest();test.test();}}

而在外部类的外部,要生成(new)一个内部类对象,需要首先建立一个外部类对象(外部类可用),然后在生成一个内部类对象。内部类的类名是外部类类名.内部类类名。

publicclassTestMenber{

publicstaticvoidmain(String[]args){

MemberInnerme=newMemberInner();MemberInner.Testtest=me.newTest();test.test();}}

2、静态内部类

静态内部类定义在类中,任何方法外,用staticclass定义。静态内部类只能访问外部类的静态成员。

生成(new)一个静态内部类对象不需要外部类对象:这是静态内部类和成员内部类的区别。

静态内部类的对象可以直接生成:Outer.Innerin=newOuter.Inner();

而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。

//外部类的内部

publicclassStaticInner{

wangzg@tarena.com.cn

privateinti1=0;

privatestaticinti2=0;privatestaticclassStaticIn{publicvoidtest(){

//i1=1;//static内部类只能使用static变量i2=1;

System.out.println(i2);}}

publicstaticvoidmain(String[]args){StaticInsi=newStaticIn();si.test();

}}

//外部类的外部

publicclassTestStatic{

publicstaticvoidmain(String[]args){

StaticInner.StaticInst=newStaticInner.StaticIn();st.test();}}

3、局部内部类

在方法中定义的内部类称为局部内部类。

与局部变量类似,在局部内部类前不加修饰符public和private,其范围为定义它的代码块。注意:

局部内部类不仅可以访问外部类私有实例变量,还可以访问外部类的局部常量(也就是局部变量必须为final的)

在类外不可直接访问局部内部类(保证局部内部类对外是不可见的)。在方法中才能调用其局部内部类。

通过内部类和接口达到一个强制的弱耦合,用局部内部类来实现接口,并在方法中返回接口类型,使局部内部类不可见,屏蔽实现类的可见性。publicclassLocalInner{inti1=0;

staticinti2=0;

publicvoidtest(inti3){

finalinti4=0;//可以使用final的局部变量classLocalIn{

publicvoidtest1(){System.out.println(i1);System.out.println(i2);//System.out.println(i3);

wangzg@tarena.com.cn

System.out.println(i4);}}

System.out.println(i4);LocalInli=newLocalIn();li.test1();}

publicstaticvoidmain(String[]args){LocalInnerli=newLocalInner();li.test(3);}}

4、匿名内部类

匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口或继承某个类,并只创建一次。匿名内部类的特点:

(1)一个类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的事先或是覆盖。

(2)只是为了获得一个对象实例,不许要知道其实际类型。(3)类名没有意义,也就是不需要使用到。

注:一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。

因其为局部内部类,那么局部内部类的所有限制都对其生效。匿名内部类是唯一一种无构造方法类。大部分匿名内部类是用于接口回调用的。

匿名内部类在编译的时候由系统自动起名Out$1.class。

如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。因匿名内部类无构造方法,所以其使用范围非常的有限。匿名内部类的写法:

publicinterfaceAnnFace{voidtest();}

publicclassTestAnn{

publicvoidgo(AnnFaceaf){af.test();}

publicstaticvoidmain(String[]args){TestAnnta=newTestAnn();ta.go(newAnnFace(){@Override

publicvoidtest(){

System.out.println(\"ann\");}

wangzg@tarena.com.cn

});}}

注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。__

因篇幅问题不能全部显示,请点此查看更多更全内容