本文主要是介绍Java基础入门 【第七章 抽象、接口、内部类、枚举】(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
匿名内部类书写格式:
父类或接口类型变量名=new父类或接口(构造方法实参列表){
//重写所有的抽象方法
@Override
public返回值类型method1(形参列表){
方法体实现
}
@Override
public返回值类型method2(形参列表){
方法体实现
}
//省略...
};
//匿名内部类对象调用方法
变量名.重写方法(实参列表);
匿名内部类的俩种形式:利用父类,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个父类的子类型
利用接口,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个接口的实现类
匿名内部类注意事项:匿名内部类必须依托于一个接口或一个父类(可以是抽象类,也可以是普通类)
匿名内部类在声明的同时,就必须创建出对象,否则后面就没法创建了匿名内部类中无法定义构造器
1)匿名内部类实现接口案例定义ISleep接口,然后通过匿名内部类对象调用方法。13.chap07.test;
//定义接口
interfaceISleep{voidsleep();
}
//匿名内部类基础测试
publicclassTest034_Interface{
41publicstaticvoidmain(String[]args){
//1.正常写法
ISleeps1=newISleep(){@Override
publicvoidsleep(){
System.out.println("躺着睡");}
};s1.sleep();System.out.println("------------");
//2.简化写法
ISleeps2=newISleep(){@Override
publicvoidsleep(){
System.out.println("趴着睡");}
};s2.sleep();System.out.println("------------");
//3.进一步简化写法
//匿名内部类对象直接调用抽象方法newISleep(){
@Override
publicvoidsleep(){
System.out.println("水里面睡");}
}.sleep();}}
//运行效果:躺着睡
------------
趴着睡
------------
水里面睡
2)匿名内部类实现抽象类案例
.chap07.test;
//定义抽象类
abstractclassMyThread{
//抽象方法
publicabstractvoidrun();
//普通方法
publicvoidtest(){
System.out.println("inMythread,test...");}
}
publicclassTest034_Abstract{
publicstaticvoidmain(String[]args){
//1.普通写法
MyThreadth=newMyThread(){@Override
publicvoidrun(){
System.out.println("重写run1");
}
};
th.run();th.test();System.out.println("--------------");
//2.简化写法
newMyThread(){
publicvoidrun(){
System.out.println("inrun2...");}
}.run();
//注意,匿名对象只能使用一次,因为没有名字,无法再次访问37}
}
//运行效果:重写run1
inMythread,test...
--------------inrun2...
3)匿名内部类对象使用父类构造方法案例
.chap07.test;
abstractclassAnimal3{privateStringname;
publicAnimal3(){}
publicAnimal3(Stringname){this.name=name;
}
publicStringgetName(){returnname;
}
//抽象方法
publicabstractvoideat();publicabstractvoidsleep();41
}
publicclassTest034_Constructor{
publicstaticvoidmain(String[]args){
//实例化匿名内部类对象
Animal3a=newAnimal3(){
//必须重写所有的抽象方法@Override
publicvoideat(){
//注意:匿名内部类属于子类,在重写方法中可通过super
关键字访问父类方法或成员
System.out.println(super.getName()+"喜欢吃鱼");
}
@Override
publicvoidsleep(){
System.out.println(super.getName()+"睡觉");}
};
//父类引用调用重写方法a.sleep();
a.eat();
System.out.println("---------------");
//实例化子类对象,调用父类构造器对父类进行初始化newAnimal3("小汤姆"){
//必须重写所有的抽象方法@Override
publicvoideat(){
//注意:匿名内部类属于子类,在重写方法中可通过super
关键字访问父类方法或成员
System.out.println(super.getName()+"喜欢抓老鼠吃");
}
@Override
publicvoidsleep(){
System.out.println(super.getName()+"睡觉");
}}.eat();
}
}
//运行效果:null睡觉
null喜欢吃鱼
---------------
小汤姆喜欢抓老鼠吃
内部类应用场景选择:考虑这个内部类,如果需要反复的进行多次使用(必须有名字)在这个内部类中,如果需要定义静态的属性和方法,选择使用静态内部类在这个内部类中,如果需要访问外部类的非静态属性和方法,选择使用成员内部类
考虑这个内部类,如果只需要使用一次(可以没有名字)选择使用匿名内部类
局部内部类,几乎不会使用
4包装类
Java中有八种基本数据类型,它们只能表示一些最简单的数字,这些数字最小的在内存中占1个字节8位,最大占8个字节64位。这些都是简单的数字,不是对象,所以不能用来调用方法或者属性,功能不够强大。
概述针对这八种基本类型,JavaAPI又专门提供了对应的类类型,目的就是为了分别把这八种基本类型的数据,包装成对应的类类型,这时候就变成对象了,就可以调用方法了或者访问属性了。
基本类型 | 包装类型 |
boolean | java.lang.Boolean |
byte | java.lang.Byte |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
char | java.lang.Character |
基础案例在这些包装类型中,都定义相关的属性和方法,例如Integer中:
.chap07.test;
publicclassTest042_Integer{
publicstaticvoidmain(String[]args){inti=1;
//编译报错,因为i不是对象
//i.toString();
//1.int-->Integer
//Integero=newInteger(i);Integero=Integer.valueOf(1);
//2.Integer-->intintj=o.intValue();System.out.println(o.toString());
//3.包装类静态成员访问System.out.println(Integer.MIN_VALUE);System.out.println(Integer.MAX_VALUE);//4.包装类静态方法调用
//把100分别转为十进制、二进制、八进制、十六进制的字符串形式System.out.println(Integer.toString(100));System.out.println(Integer.toString(100,2));System.out.println(Integer.toString(100,8));System.out.println(Integer.toString(100,16));//把100转为二进制形式System.out.println(Integer.toBinaryString(100));
//把字符串"100"转为int类型的100
intnum=Integer.parseInt("100");
System.out.println(num);
}
}注意:一定要掌握publicstaticintparseInt(Strings)方法。
装箱拆箱JDK1.5或以上,可以支持基本类型和包装类型之间的自动装箱、自动拆箱,这简化了基本类型和包装类型之间的转换。
自动装箱:基本数据类型值自动转化为包装类对象
自动拆箱:包装类对象自动转化为基本数据类型值
案例展示:int、Integer自动装箱拆箱展示。
.chap07.test;
publicclassTest043_Integer{
publicstaticvoidmain(String[]args){
//JKD1.5之前
//Integero=newInteger(1);
//Integero=Integer.valueOf(1);
//JDK1.5之后
//自动装箱,这里会自动把数字1包装成Integer类型的对象Integero=1;
//JKD1.5之前
//Integero=newInteger(1);
//inti=o.intValue();
//JDK1.5之后
//Integero=newInteger(1);
//自动拆箱,这里会自动把对象o拆箱为一个int类型的数字,并把数字赋值给int类型的变量i
inti=o;}
}其他的基本类型和包装类型之间的转换,与此类似
注意事项:使用基本类型和包装类时,要考虑隐式类型转换。不同类型的基本数据类型和包装类,是不可以自动装箱拆箱的,例如int和Long。具体案例如下:
.chap07.test;
publicclassTest043_Test{publicvoidtest1(inti){}
publicvoidtest2(Integeri){}publicvoidtest3(longi){}publicvoidtest4(Longi){
}
publicstaticvoidmain(String[]args){
Test043_Testt=newTest043_Test();t.test1(1);//编译通过inti=1;正常赋值t.test2(1);//编译通过Integeri=1;自动装箱t.test3(1);//编译通过longi=1;隐式类型转换
//编译报错
//错误的代码:Longi=1;
//int和Long之间没有任何关系
//t.test4(1);
t.test4(1L);//编译通过Longi=1L;自动装箱}29}
Integer缓冲区在Java中方法区有一个叫做运行时常量池(RuntimeConstantPool)的区域,用于存储编译期间生成的各种字面量和符号引用,Integer常量池就存在运行时常量池里面。Integer常量池是一个特殊的缓存机制,用于存储在范围[-128,127]之间的Integer常量对象。这个范围是Java中的一个固定范围,超出这个范围的整型常量不会被缓存。当使用自动装箱(Autoboxing)将一个整数赋值给一个Integer对象时,如果该整数在[-128,127]范围内,那么会从Integer常量池中获取一个已经存在的对象,而不是创建一个新的对象。这是因为在这个范围内的整数常见且频繁使用,通过复用对象可以节省内存空间和提高性能。
基础知识补充:
在实现下面案例之前,我们先学习java.lang.System类中的一个方法:
publicstaticnativeintidentityHashCode(Objectx);该方法会返回对象的哈希码,即Java根据对象在内存中的地址计算出来一个整数值,不同的地址算出来的结果是不一样的。注意,哈希码并不是对象的内存地址。验证案例:
publicclassTest044_Cache{
publicstaticvoidmain(String[]args){Integeri1=newInteger(127);Integeri2=newInteger(127);System.out.println("i1:"+
System.identityHashCode(i1));System.out.println("i2:"+
System.identityHashCode(i2));
System.out.println("i1==i2:"+(i1==i2));
//false
System.out.println("--------------");
Integeri3=127;Integeri4=127;
System.out.println("i3:"+System.identityHashCode(i3));
System.out.println("i4:"+System.identityHashCode(i4));
System.out.println("i1==i3:"+(i1==i3));
//false
System.out.println("i3==i4:"+(i3==i4));
//true
System.out.println("--------------");
Integeri5=128;Integeri6=128;
System.out.println("i5:"+System.identityHashCode(i5));
System.out.println("i6:"+System.identityHashCode(i6));
System.out.println("i5==i6:"+(i5==i6));
//false}
}
运行效果:
Integer对象内存构成:结果分析:
i1==i2结果为false,图上很清楚,无需多解释。i3==i4结果为true,因为127在[-128,127]这个范围中,i3和i4直接复用了常量池中Integer(127)对象,故而两者哈希码值相同,==比较也相同。i5==i6结果为false,因为128不在[-128,127]这个范围中,i5和i6自动装箱过程中,系统底层执行了Integeri5=newInteger(128);
Integeri6=newInteger(128);,故而i5和i6指向2个不同的对象。Integer源码分析:
packagejava.lang;
publicfinalclassIntegerextendsNumberimplementsComparable<Integer>{
//省略...
/**
*Cachetosupporttheobjectidentitysemanticsofautoboxingforvaluesbetween128and127(inclusive)asrequiredbyJLS.
*/
privatestaticclassIntegerCache{staticfinalintlow=-128;staticfinalinthigh;
staticfinalIntegercache[];
static{
//highvaluemaybeconfiguredbypropertyinth=127;//省略...
high=h;
cache=newInteger[(high-low)+1];intj=low;
for(intk=0;k<cache.length;k++)cache[k]=newInteger(j++);//range[-128,127]mustbeinterned(JLS75.1.7)assertIntegerCache.high>=127;
}
privateIntegerCache(){}}//省略...
}
5 Object类
Object类是所有类的父类型,类中定义的方法,java中所有对象都可以调用
toString该方法前面课程已经讲过,其可以返回一个对象默认的字符串形式。
packagejava.lang;
/**
*Class{@codeObject}istherootoftheclasshierarchy.*Everyclasshas{@codeObject}asasuperclass.All
objects,*/
publicclassObject{
//省略...
publicStringtoString(){
returngetClass().getName()+"@"+Integer.toHexString(hashCode());
}
}
子类中可以对该方法进行重写:13
publicclassStudent{privateStringname;privateintage;
//重写方法
@Override
publicStringtoString(){
return"Student[name="+name+",age="+age+"]";}10
}
//注意,输出对象时,自动调用对象.toString()方法
Students1=newStudent();
//下面两行效果相同System.out.println(s1);System.out.println(s1.toString());
equals该方法可以比较俩个对象是否相等(重点掌握)
源码如下:packagejava.lang;
publicclassObject{
/**
*Indicateswhethersomeotherobjectis"equalto"thisone.
*默认比较的是两个对象堆内存地址值,实际开发中,我们往往需要重写该方法,比较对象属性值。
*/
publicbooleanequals(Objectobj){return(this==obj);
}
}可以看出,Object中的equals方法,是直接使用的==号进行的比较,比较俩个对象的地址值是否相等
案例1:定义Stu类,包含name和age属性,创建两个对象进行equals比较。】
.chap07.test;
classStu{
privateStringname;privateintage;publicStu(){}
publicStu(Stringname,intage){super();
this.name=name;this.age=age;
}
//get|set省略...
}
publicclassTest053_Equals{
publicstaticvoidmain(String[]args){Stus1=newStu("tom",20);
Stus2=newStu("tom",20);
System.out.println("s1==s2:"+(s1==s2));
//false
System.out.println(s1.equals(s2));
//false}
}
//运行效果:s1==s2:falsefalse
结果分析:s1==s2结果为false,==比较的是对象的引用,即比较两个对象是否指向内存中的同一个地址。s1和s2是两个不同对象,不指向同一个地址,故而结果false。s1.equals(s2)结果为false,Stu没有重写equals方法,默认使用==比较s1
和s2,结果false。
案例2:在上述案例的基础上,重写Stu类中的equals方法,比较对象的属性值是否相同,然后运行测试。
.chap07.test;
publicclassTest053_Equals{
publicstaticvoidmain(String[]args){Stus1=newStu("tom",20);
Stus2=newStu("tom",20);
System.out.println("s1==s2:"+(s1==s2));
//false
System.out.println(s1.equals(s2));
//false}
}
classStu{
privateStringname;privateintage;
publicStu(){}
publicStu(Stringname,intage){super();
21this.name=name;this.age=age;
}
publicStringgetName(){returnname;
}
publicvoidsetName(Stringname){this.name=name;
}
publicintgetAge(){returnage;
}
publicvoidsetAge(intage){this.age=age;
}
//重写equals方法
@Override
publicbooleanequals(Objectobj){booleanflag=false;//1.obj类型判断,如果不是Stu则返回false
if(!(objinstanceofStu))returnfalse;//向下转型
Stus=(Stu)obj;
//2.如果比较的两个对象指向同一块内存(同一个对象)
if(this==obj)returntrue;//3.属性值比较,如果姓名年龄全都相同,则修改返回标志为true
if(name.equals(s.getName())
&&(age==s.getAge()))
flag=true;
returnflag;59}
}
//运行效果:s1==s2:falsetrue
注意:一般情况下,程序员不需要手动重写equals方法,STS中提供了自动生成(建议)的快捷键。Alt+Shift+S,然后选择操作即可:
自动生成代码如下:
@Override
publicbooleanequals(Objectobj){if(this==obj)
returntrue;if(obj==null)
returnfalse;
if(getClass()!=obj.getClass())returnfalse;
Stuother=(Stu)obj;if(age!=other.age)
returnfalse;
if(name==null){
if(other.name!=null)returnfalse;
}elseif(!name.equals(other.name))returnfalse;
returntrue;27
}
@Override
publicinthashCode(){finalintprime=31;intresult=1;
result=prime*result+age;
result=prime*result+((name==null)?0:name.hashCode());
returnresult;}
hashCode该方法的具体细节,我们在集合章节再补充,现阶段大家大致了解即可!该方法返回一个int值,该int值是JVM根据对象在内存的中的特征(地址值),通过哈希算法计算出的一个结果。Hash,一般翻译做“散列”,也可以音译为“哈希”,就是把任意长度的数据输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。一个任意长度的输入转为一个固定长度的输出,是一种压缩映射,也就是说,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。
注意:通常情况下我们认为Object中hashCode方法返回的是对象的内存地址值,但实际上并不是。
hashCode源码:13packagejava.lang;
publicclassObject{
/**
*Returnsahashcodevaluefortheobject.Thismethodis
*supportedforthebenefitofhashtablessuchasthoseprovidedby
*{@linkjava.util.HashMap}.*/
publicnativeinthashCode();}
引用变量的hashCode值:
俩个引用变量指向同一个对象,则它们的hashCode值一定相等俩个引用变量的hashCode值相同,则它们有可能指向同一个对象,也可能指向不同对象
俩个引用变量的hashCode值不同,则它们肯定不可能指向同一个对象
在自定义类中,如果需要重写equals方法的话,我们一般会同时重写hashCode(),建议使用STS自动生成重写代码(equals章节已经讲过)。
getClass该方法的具体细节,我们在反射章节再补充,现阶段大家大致了解即可!该方法是非常重要的一种方法,它返回引用变量在运行时所指向的字节码对象。该方法是native修饰的本地方法,不是Java语言实现的。
源码如下:
packagejava.lang;
publicclassObject{
//省略...
/**
*获取类的字节码对象(反射部分会专门学习)
*Returnstheruntimeclassofthis{@codeObject}.Thereturned
*{@codeClass}objectistheobjectthatislockedby{@code
*staticsynchronized}methodsoftherepresentedclass.*/
publicfinalnativeClass<?>getClass();}注意:子类中不能重写getClass,调用的一定是Object中的getClass方法。
.chap07.test;
publicclassTest052_GetClass{
publicstaticvoidmain(String[]args){Test052_GetClasstg=newTest052_GetClass();System.out.println(tg.getClass());
}
}
//运行结果
classcom.briup.chap07.test.Test052_GetClass
6 String类
字符串String,是程序中使用最多的一种数据,JVM在内存中专门设置了一块区域(字符串常量池),来提高字字符串对象的使用效率。
概述在Java中,String是一个类,用于表示字符串,它是Java中最常用的类之一,用于处理文本数据。
String基础内容:String类在java.lang包下,所以使用的时候不需要导包Java程序中所有字符串字面值(如"abc")都是String类对象字符串值不可变,String对象是不可变的,一旦创建,它们的值就不能被修改
常用构造方法:
案例展示:
21.chap07.test;
publicclassTest061_Basic{
publicstaticvoidmain(String[]args){
//publicString():创建一个空白字符串对象,不含有任何内容
Strings1=newString();System.out.println(s1);
//publicString(char[]chs):根据字符数组的内容,来创建字符串对象
char[]chs={'a','b','c'};Strings2=newString(chs);System.out.println(s2);//publicString(Stringoriginal):根据传入的字符串内容,来创建字符串对象
Strings3=newString("123");System.out.println(s3);
Strings4="hello";System.out.println(s4);
}
}
注意,字符串对象创建以后,堆空间中字符串值不可以被修改,具体如下图:
常量池问题引入:创建字符串对象,和其他普通对象一样,会占用计算机的资源(时间和空
间),作为最常用的数据类型,大量频繁的创建字符串对象,会极大程度地影响程序的性能。
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化为字符串开辟一个字符串常量池,类似于缓存区创建字符串常量时,首先会检查字符串常量池中是否存在该字符串,如果存在该字符串,则返回该实例的引用,如果不存在,则实例化创建该字符串,并放入池中
String常量池:在Java中,String常量池是一块特殊的内存区域,用于存储字符串常量。String常量池的设计目的是为了节省内存和提高性能。
当我们创建字符串常量时,如果字符串常量池中已经存在相同内容的字符串,那么新创建的字符串常量会直接引用已存在的字符串对象,而不会创建新的对象。这样可以避免重复创建相同内容的字符串,节省内存空间。在JDK8及之后的版本中,字符串常量池的位置与其他对象的存储位置,都位于堆内存中。这样做的好处是,字符串常量池的大小可以根据需要进行调整,并且可以享受到垃圾回收器对堆内存的优化。
Java将字符串放入String常量池的方式:直接赋值:通过直接赋值方式创建的字符串常量会被放入常量池中。例如:Stringstr="Hello";
调用String类提供intern()方法:可以将字符串对象放入常量池中,并返回
常量池中的引用。例如:Stringstr=newString("World").intern();
注意:通过new关键字创建的字符串对象不会放入常量池中,而是在堆内存中创建一个新的对象。只有通过直接赋值或调用intern()方法才能将字符串放入常量池中。
案例1:13.chap07.test;
publicclassTest062_String{
publicstaticvoidmain(String[]args){
Strings1="Hello";//字符串常量,放入常量池Strings2="Hello";//直接引用常量池中的字符串对象System.out.println(s1==s2);//true,引用相同
//直接newString对象,不会将'World'放入常量池Strings3=newString("World");
//调用intern()方法,将'World'放入常量池,并返回常量池中的引用
Strings4=newjava.lang.String("World").intern();
Strings5="World";
System.out.println(s3==s4);//false,引用不同System.out.println(s4==s5);//true,引用相同19}
案例2
.chap07.test;
publicclassTest062_String2{
publicstaticvoidmain(String[]args){Strings1="a";
Strings2="b";
//常量优化机制:"a"和"b"都是字面值常量,借助+连接,其结果"ab"也被当作常量
Strings3="a"+"b";Strings4="ab";System.out.println(s3.equals(s4));//trueSystem.out.println(s3==s4);//trueSystem.out.println("-------------");
Strings5=s1+s2;System.out.println(s4.equals(s5));//trueSystem.out.println(s4==s5);//false
System.out.println("-------------");
Strings6=(s1+s2).intern();System.out.println(s4.equals(s6));//trueSystem.out.println(s4==s6);//true26}
}
注意事项:使用+拼接多个字符串常量,拼接的结果仍旧是字符串常量如果结果字符串常量在常量池中不存在,则Java会将其放入到字符串常量池中
12//final常量测试
publicstaticvoidmain(String[]args){Stringstr="ab";//final修饰的String常量finalStringstr1="a";Stringstr2=str1+"b";System.out.println(str==str2);}//结果为true
常见方法
String源码:
packagejava.lang;
publicfinalclassString
implementsjava.io.Serializable,Comparable<String>,CharSequence{
/**Thevalueisusedforcharacterstorage.*/
privatefinalcharvalue[];
//省略...
//获取字符串字符个数
publicintlength();
//比较字符串的内容,严格区分大小写
publicbooleanequals(ObjectanObject);
//返回指定索引处的char值
publiccharcharAt(intindex);
//将字符串拆分为字符数组后返回
publicchar[]toCharArray();
//根据传入的规则切割字符串,得到字符串数组publicString[]split(Stringregex);
//根据开始和结束索引进行截取,得到新的字符串[begin,end)
publicStringsubstring(intbegin,intend);
//从传入的索引处截取,截取到末尾,得到新的字符串
[begin,str.length())
publicStringsubstring(intbegin);
//使用新值,将字符串中的旧值替换,得到新的字符串
publicStringreplace(CharSequencetarget,CharSequencereplacement);
}
基础案例1:从键盘录入一行字符串,获取其长度和索引2位置上的字符,最后统计字符串中数字字符的个数。
.chap07.test;importjava.util.Scanner;publicclassTest063_Function{
publicstaticvoidmain(String[]args){
//1.实例化sc对象,获取从键盘录入整行字符串Scannersc=newScanner(System.in);System.out.println("inputstring:");Stringstr=sc.nextLine();
24//2.获取字符串长度及索引2上的字符System.out.println("length:"+str.length());System.out.println("charAt(2):"+str.charAt(2));
//3.统计字符串中数字字符的个数
char[]array=str.toCharArray();intcount=0;
for(charc:array){
if(c>'0'&&c<'9'){
count++;}
}
System.out.println("数字字符个数:"+count);25}
}
登录案例2:假设用户名和密码是"admin"和"briup",从键盘录入用户名和密码,如果匹配成功则输出"登录成功",否则输出"登录失败,用户名或密码有误!"
publicstaticvoidmain01(String[]args){
//1.实例化sc对象
Scannersc=newScanner(System.in);
//2.从键盘分别录入用户名和密码System.out.println("inputusername:");Stringusername=sc.nextLine();System.out.println("inputpassword:");Stringpassword=sc.nextLine();
//3.登录校验
//注意:一般字符串常量值.equals方法,防止空指针异常
if("admin".equals(username)
&&"briup".equals(password)){
System.out.println("登录成功!");
}else{
System.out.println("登录失败,用户名或密码错误!");
}
}
字符串拆分案例3:从键盘录入学生的信息,格式为:学号:姓名:分数,例:001:zs:78,请拆分学生信息并输出。
publicstaticvoidmain(String[]args){
//1.实例化sc对象,获取从键盘录入学生信息Scannersc=newScanner(System.in);System.out.println("inputstudentmsg:");
//001:zs:78
Stringstr=sc.nextLine();
//2.按照:进行分割
String[]arr=str.split(":");
//3.输出学生基本信息System.out.println("id:"+arr[0]);System.out.println("name:"+arr[1]);//注意,分数为int类型,需要String-->intintscore=Integer.parseInt(arr[2]);System.out.println("score:"+score);
}
字符串拆分案例4:
从键盘录入学生的信息,格式为:学号.姓名.分数,例:001.zs.78,请拆分学生信息并输出。注意:相对上面案例,当前案例中分隔符为.属于特殊符号,使用时需去除其特殊含义。
publicstaticvoidmain(String[]args){
//1.实例化sc对象,获取从键盘录入学生字符串Scannersc=newScanner(System.in);System.out.println("inputstudentmsg:");
//001.zs.78
Stringstr=sc.nextLine();
//2.字符串拆分
//特殊含义的字符,作为分隔符,需要去除其特殊含义,下面两种方式
//String[]arr=str.split("\\.");String[]arr=str.split("[.]");System.out.println("id:"+arr[0]);System.out.println("name:"+arr[1]);intscore=Integer.parseInt(arr[2]);System.out.println("score:"+score);
}
字符串截取案例5:从键盘录入一个手机号,将中间四位号码修改为****输出,如键盘录入13800001234,处理后最终效果为:138****1234。
publicstaticvoidmain(String[]args){
//1.实例化sc对象,获取手机字符串
Scannersc=newScanner(System.in);System.out.println("inputtel:");Stringtel=sc.nextLine();
//2.截取字符串前三位
Stringstart=tel.substring(0,3);
//3.截取字符串后四位
Stringend=tel.substring(7);
//4.将截取后的两个字符串,中间加上****进行拼接,输出结果
System.out.println(start+"****"+end);15}字符串替换案例6:用字符串替换replace方法,重新实现上述功能。
publicstaticvoidmain(String[]args){
//1.实例化sc对象,获取手机字符串
Scannersc=newScanner(System.in);System.out.println("inputtel:");Stringtel=sc.nextLine();
//2.截取字符串中间4位
Stringmid=tel.substring(3,3+4);
//3.用****替换中间4位,得到新tel
StringnewTel=tel.replace(mid,"****");
//4.输出新tel
System.out.println("newTel:"+newTel);}
其他String相关方法,自行参考API学习使用。
7 枚举枚举类概述
枚举,是JDK1.5引入的新特性,可以通过关键字enum来定义枚举类。枚举类意义
1)Java中的类,从语法上来说,可以创建无数个对象例如,学生类Student,我们可以创建出10个、20个或更多数量的学生对象,并且从实际业务上讲也没有问题,因为实际情况中确实会存在很多不同的学生。
2)Java特殊类,其所能创建的对象个数是固定的例如,性别类Gender,表示人的性别,从语法上来说,可以创建出无数个性别对象,但是从实际意义上看,我们只需要创建2个对象就可以了:性别男、性别女。
3)如何实现上述Java特殊类我们可以将Gender定义为一个枚举类型(enum),在枚举类型中,我们需要提前定义枚举元素(枚举类型对象固定的几个取值),以后开发过程中只能使用枚举元素给Gerder类对象赋值。例如:
.chap07.test;
//1.定义枚举类
enumGender{
MALE,FEMALE6
}
publicclassTest071_EnumBasic{
publicstaticvoidmain(String[]args){
//2.枚举类实例化对象
//固定格式:枚举类引用名=枚举类.枚举元素值;
Genderg1=Gender.MALE;Genderg2=Gender.MALE;System.out.println(g1);System.out.println(g2);System.out.println("-------------");
Genderg3=Gender.FEMALE;Genderg4=Gender.FEMALE;System.out.println(g3);System.out.println(g4);//3.错误用法:枚举对象的取值,只能是枚举元素
//Genderg5=Gender.BOY;error}
}
//输出枚举对象,默认输出枚举元素名称字符串
MALE
MALE
-------------FEMALE
FEMALE
上述案例中,我们定义了枚举类Gender,有且只有俩个对象:MALE、FEMALE。
4)枚举类分析找到Gender类编译生成的字节码文件,对其反编译,观察枚举类定义细节,具体如下:Gender.class文件位置:
反编译命令:javap-pGender.class结合上图我们可知:枚举类Gender本质上是一个final修饰的类,不可以被继承枚举类会默认继承java.lang.Enum这个抽象泛型类
packagejava.lang;
publicabstractclassEnum<EextendsEnum<E>>
implementsComparable<E>,Serializable{
//枚举元素名
privatefinalStringname;
publicfinalStringname(){
9 returnname;
}
//枚举元素编号,从0开始
privatefinalintordinal;
publicfinalintordinal(){
returnordinal;}//...省略20}
枚举元素,本质上是枚举类对象,且由static和final修饰枚举类提供私有构造器,我们在类外不能主动创建枚举类对象枚举类中可以包含publicstatic静态方法
其他细节我们暂不考虑
枚举基本定义定义格式:
[修饰符]enum枚举类名{
枚举元素1,枚举元素2,...枚举元素n;}
案例展示:定义枚举类Week,要求包含多个枚举元素。1.chap07.test;
//枚举类基本定义
enumWeek{
//枚举元素必须写在第一行,如果有多个的话,用逗号','隔开,
//最后用分号';'结束
//如果';'后面没有其他内容的话,';'可以省略,但不建议省略
MON,TUE,WED;//WED()
//WED和WED()效果一样,含义为:执行枚举类默认构造器去实例化枚举元素对象
//源代码类似:publicstaticfinalWeekWED=newWeek();
//注意:用户没有提供构造器,系统会提供默认的构造器privateWeek()
{}
}
publicclassTest072_Define01{
publicstaticvoidmain(String[]args){
//1.枚举元素引用格式:枚举类名.枚举元素名;
//注意枚举类名不能省略Weekw1=Week.MON;Weekw2=Week.TUE;Weekw3=Week.WED;
//2.输出枚举对象,默认输出枚举元素名System.out.println(w1);System.out.println(w2.toString());
System.out.println("-----------");
//3.获取枚举元素名:跟元素名一样的同名字符串
System.out.println(w3.name());
//4.获取枚举元素编号:从0开始,逐个加1System.out.println(w1.ordinal());//0
System.out.println(w2.ordinal());//1
System.out.println(w3.ordinal());//2
}
构造方法定义包含数据成员、构造方法的枚举类.
定义格式:[修饰符]enum枚举类名{
枚举元素1(实际参数列表),...枚举元素n(实际参数列表);
//枚举类数据成员和成员方法,可以包含多个[修饰符]数据类型数据成员名;[修饰符]返回值类型成员方法名(形参列表){方法体实现;
}
//枚举类构造方法,可以包含多个
//注意,必须使用private进行修饰private构造方法;
}
案例展示:定义枚举类Week2,要求包含私有数据成员desc和构造方法。
MON,TUE(),WED("星期三");
/*源代码描述:
*publicstaticfinalWeekMON=newWeek();
*publicstaticfinalWeekTUE=newWeek();
*publicstaticfinalWeekWED=newWeek("星期三");*/
//枚举类数据成员和成员方法,可以包含一个或多个
privateStringdesc;
publicStringgetDesc(){returndesc;
}
publicvoidsetDesc(Stringdesc){this.desc=desc;
}
//枚举类构造方法,如果不提供,系统会提供默认构造方法,private修饰
//如果用户自定义枚举类构造方法,则系统不再提供
privateWeek2(){}
//自定义枚举方法,注意必须用private修饰
privateWeek2(Stringdesc){this.desc=desc;
}
}
publicclassTest073_Define02{
publicstaticvoidmain(String[]args){Week2w1=Week2.MON;System.out.println(w1);System.out.println("------------");
Week2w2=Week2.TUE;
System.out.println(w2);System.out.println("w2.desc:"+w2.getDesc());System.out.println("------------");
Week2w3=Week2.WED;System.out.println(w3);
System.out.println("w3.desc:"+w3.getDesc());51}
52}
抽象方法定义包含抽象方法的枚举类
.定义格式:
[修饰符]enum枚举类名{枚举元素1(实参列表){
重写所有抽象方法;
},...枚举元素n(实参列表){重写所有抽象方法;
};
//可以包含多个抽象方法抽象方法声明;//数据成员、成员方法及构造方法略...
}
案例展示:定义枚举类Week3,要求包含抽象方法show()。
.chap07.test;
//定义枚举类的第三种情况:包含抽象方法
enumWeek3{
//注意:包含抽象方法的枚举类是抽象类,不能直接实例化对象
//所以定义枚举类元素(所有)时候,一定要重写抽象方法
//注意:必须在所有的枚举元素定义中,重写所有抽象方法
//MON{MON(){
//在枚举元素中重写抽象方法@Override
publicvoidshow(){
System.out.println("inshow,MON:周一");
}
},TUE("星期二"){
//注意,每个枚举元素中都要重写重写方法,且要重写所有的抽象方法
@Override
publicvoidshow(){System.out.println("inshow,TUE:"+
this.getDesc());}
};
//枚举类数据成员及get方法
privateStringdesc;
publicStringgetDesc(){returndesc;
}
//枚举类自定义构造方法
privateWeek3(){}
privateWeek3(Stringdesc){this.desc=desc;
}
//枚举类包含的抽象方法(可以0或多个)publicabstractvoidshow();39
}
publicclassTest074_Define03{
publicstaticvoidmain(String[]args){Week3w1=Week3.MON;System.out.println(w1);
w1.show();
System.out.println("------------------");
Week3w2=Week3.TUE;System.out.println(w2);w2.show();
}
}
枚举总结在实际项目开发中,我们定义枚举类型,大多数情况下使用最基本的定义方式,偶尔会添加属性、方法和构造方法,并不会写的那么复杂。
枚举类注意事项:
定义枚举类要使用关键字enum所有枚举类都是java.lang.Enum的子类枚举类的第一行上必须是枚举元素(枚举项)最后一个枚举项后的分号是可以省略的,但是;后面还有其他有效代码,这个分号就不能省略,建议不要省略
用户如果不提供构造方法,系统会提供默认的构造方法:private枚
举类(){}用户可以提供构造方法,但必须用private修饰,同时系统不再提供默认构造方法
枚举类也可以有抽象方法,但是枚举元素必须重写所有抽象方
第七章就结束了,友友们,加油,霍尔最近有点累,但霍尔祝你们有个好心情哦!
这篇关于Java基础入门 【第七章 抽象、接口、内部类、枚举】(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!