22.面向对象之多态
1.多态:从现实世界事物描述一个事物体现出的不同形态;从程序中描述这个对象在内存中的变化.
2.前提条件:
(1)必须存在继承关系
(2)必须存在方法重写,让子类完成自己业务功能,将父类的功能覆盖.
(3)需要存在父类引用指向子类对象,即:父类名 对象名 = new 子类名();
3.访问格式:
4.访问特点:
成员变量:编译看左,运行看左.
成员方法:编译看左,运行看右,存在方法重写,子类的方法覆盖了父类的方法.
静态的成员方法:编译看左运行看左,类成员,随着类的加载而加载,通过类名访问
构造方法:存在继承关系,所以父类先初始化,子类在初始化.
abstract class Fu{ int a = 10 ;//父类的成员变量 public static void function(){ System.out.println("父类的静态的成员方法"); } public void method(){ System.out.println("父类的成员方法"); } } class Zi extends Fu{ int a = 20 ;//子类的成员变量 public static void function(){ System.out.println("子类的静态的成员方法"); } @Override public void method() { System.out.println("子类的成员方法"); } } public class Test{ public static void main(String[] args){ Fu fu = new Zi(); System.out.println(fu.a); //输出a的值是10 fu.method();//输出:"子类的静态的成员方法" Fu.function();//输出:"父类的静态的成员方法" } }
5.多态的好处:
(1)可以提高代码的复用性,是由继承保证的
(2)可以提高代码的扩展性,是由多态保证的
6.多态的弊端:
多态的访问格式是向上转型的,使用的是父类的东西,不能访问子类的特有功能.
解决方案:
方法1:向下转型,父类引用指向子类对象,将父类的引用强转为子类对象.
子类名 对象名 = (子类名)父类引用;//向下转型的格式
方法2:直接创建具体的子类对象,即:子类名 对象名 = new 子类名();(但是创建具体的子类对象需要在堆内存中开辟空间,消耗了内存)
class Fu{ public void method(){ System.out.println("父类的成员方法"); } } class Zi extends Fu{ @Override//方法重写 public void method() { System.out.println("子类的成员方法"); } public void method1(){ System.out.println("子类的特有功能"); } } public class Test{ public static void main(String[] args){ Fu fu = new Zi();//父类引用指向子类对象 //fu.method1();会报错,多态的访问格式是向上转型,无法访问子类的特有功能. //方法2,创建具体的子类对象 Zi zi = new Zi(); zi.method1(); //方法1,向下转型 Zi z = (Zi)fu; z.method1(); } }
多态时期的异常:java.lang.ClassCastException(类转换异常,属于运行时期异常)
class Fu{ public void method(){ System.out.println("父类的成员方法"); } } class Zi1 extends Fu{ @Override//方法重写 public void method() { System.out.println("Zi1的成员方法"); } } class Zi2 extends Fu{ @Override//方法重写 public void method() { System.out.println("Zi2的成员方法"); } } public class Test{ public static void main(String[] args){ Fu fu = new Zi1();//父类引用指向子类对象 fu = new Zi2(); Zi1 z = (Zi1)fu;//会出现java.lang.ClassCastException异常 } }
23.抽象类
1.抽象类:如果一个类中由抽象方法,那么定义这个类为抽象类
abstract class 类名{}
2.抽象方法:没有方法体的一个成员方法,并且携带abstract关键字.
权限修饰符 abstract 返回值类型 方法名(形式参数列表);
3.抽象类的特点:不能实例化(不能创建对象)
4.抽象类的实例化:通过具体的子类进行实例化.
抽象的父类名 对象名 = new 具体的子类名() ;
5.与abstract冲突的关键字:
private:被private修饰的成员方法只能在本类中访问,而abstract关键字会强制子类重写.
final:被final修饰的成员不能被重写,而abstract关键字会强制子类重写.
static:被static修饰的方法需要被类名访问,随着类的加载而加载,而abstract关键字会强制子类重写.
6.方法重写的注意事项:子类继承父类重写父类的方法时,访问权限不能比父类低,和父类保持一致.
7.注意事项:
(1)在一个类中,如果当前类存在抽象功能(方法),那么这个类必须是抽象类.
(2)一个抽象类中,不一定都是抽象方法.
(3)抽象的子类为具体类时才可以创建实例;为抽象类时没有意义.
(4)抽象类的本质是强制子类必须完成的事情.
8.成员特点:
成员变量:既可以是常量,也可以是变量.
成员方法:既可以是抽象方法,也可以是非抽象方法
构造方法:目的是对数据进行初始化;分层初始化
24.接口
1.接口:描述事物本身之外的额外功能,比抽象类还抽象
interface 接口名{} //接口命名规则:大驼峰命名法 //interface:关键字
2.接口的抽象方法没有方法体
3.implements关键字:实现接口
4.注意事项:
(1)接口的子类可以是抽象类,但是他肯定会存在最具体的子类,否则没有意义.
(2)具体类:通过接口多态进行实例化.
接口名 对象名 = new 子实现类名();
5.成员特点:
成员变量:只能是常量,存在默认修饰符public static final (可以省略)
成员方法:只能是抽象方法,存在默认修饰符public abstrsct(可以省略)
构造方法:接口没有构造方法.
6.类与类之间的关系区别
(1)类与类之间的关系:继承关系,只支持单继承,不支持多继承,单支持多成层继承.
(2)类与接口之间的关系:实现关系,一个类继承另一个类的同时,可以实现多个接口.
(3)接口与接口之间的关系:继承关系,不仅支持单继承还支持多继承,也支持多层继承.
25.instanceof:判断
对象名称 instanceOf 类名 //判断当前对象名是否时当前类的实例
26.形式参数问题
(1)方法的形式参数是基本数据类型时:实际参数传递当前具体的基本类型数值即可.
(2)方法的形式参数是引用数据类型时:
具体类:调用该方法,实际参数需要传递的是当前具体类对象.
class Person{ public void method(){ System.out.println("都需要学习"); } } class PersonDome{ public void study(Person person){//具体类作为形式参数,实际参数需要创建对象 person.method(); } } public class Test{ public static void main(String[] args) { //创建PersonDome类对象 PersonDome pd = new PersonDome(); //方式1 创建Person类对象 Person pr = new Person(); //调用Person类中的method方法 pd.study(pr);// //方式2 匿名对象 pd.study(new Person()); } }
抽象类:调用该方法,实际参数需要传递的是当前抽象类的子类对象,由抽象类多态完成.
abstract class Person{ public abstract void method(); } class Student extends Person{ @Override public void method() { System.out.println("学生需要学习!"); } } class PersonDome{ public void function(Person person){//抽象类作为形式参数 person.method(); } } public class Test{ public static void main(String[] args) { //创建PersonDome类对象 PersonDome pd = new PersonDome(); //抽象类多态,向上转型 实际参数传递当前抽象类的子类对象,抽象类多态 Person pe = new Student(); //调用PersonDome类中的function方法 pd.function(pe); } }
接口:调用该方法,实际参数需要传递的是当前接口的子实现类对象,接口多态
interface Person{ public abstract void method(); } class Student implements Person{ @Override public void method() { System.out.println("学生都需要休息!"); } } class PersonDome{ public void function(Person person){//接口作为形式参数 person.method(); } } public class Test{ public static void main(String[] args) { //创建PersonDome类对象 PersonDome pd = new PersonDome(); //创建Student类对象 实际参数传递当前接口的子实现类对象,接口多态 Person pe = new Student(); //调用PersonDome类的function方法 pd.function(pe); } }
27.返回值问题
(1)方法的返回值类型是基本数据类型:通过功能操作,返回数据值结果.
(2)方法的返回值类型是引用数据数据类型
具体类:如果一方法的返回值是一个具体类,那么该方法就需要返回当前类具体对象.
class Person{ public void method(){ System.out.println("人类需要学习!"); } } class PersonDome{ //具体类作为返回值,调用该方法时返回当前具体类对象 public Person function(){ //创建具体类对象,返回当前具体类对象 //方式1 Person pe = new Person(); return pe; //方式2 匿名对象 //return new Person(); } } public class Test { public static void main(String[] args) { //创建PersonDome类对象 PersonDome pd = new PersonDome(); //完成了Person pe = new Person Person pe = pd.function(); //调用method方法 pe.method(); } }
抽象类:如果一个方法的返回值是一个抽象类,那么该方法需要返回当前抽象类的子类对象
abstract class Person{ public abstract void study(); } class Student extends Person{ @Override public void study() { System.out.println("学生都需要学习"); } } class PersonDome{ //返回值类型是抽象类时,返回当前抽象类的子类对象 public Person Method(){ //抽象类多态 //方法1 Person pe = new Student(); return pe; //方法2 匿名对象 //return new Student(); } } public class Test{ public static void main(String[] args) { //创建PersonDome类对象 PersonDome pd = new PersonDome(); //完成了Person pe = new Student() Person pe =pd.Method(); //调用了Person类的study方法 pe.study(); } }
接口:如果一个方法的返回值类型是接口,那么该方法需要返回当前接口的子实现类对象
interface Person{ public void study(); } class Student implements Person{ @Override public void study() { System.out.println("学生都需要休息!"); } } class PersonDome{ //返回值类型是接口时,返回当前接口的子实现类对象 public Person method(){ //方法1 接口多态 Person pe = new Student(); return pe; //方法2 匿名对象 //return new Student(); } } public class Test{ public static void main(String[] args) { //创建PersonDome类对象 PersonDome pd = new PersonDome(); //完成了Person pe = new Student(); Person pe = pd.method(); //调用Person类中的study方法 pe.study(); } }
28.权限修饰符的范围
同一个包中的当前类 | 同一个包中的子类/无关类 | 不同包的子类中 | 不同包的无关类中 | |
---|---|---|---|---|
private | √ | |||
默认修饰符 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
权限修饰符的优先级:public > protected(受保护的) > 默认修饰符 > private
dos控制台带包的编译和运行(手动/自动)
同一个包下的编译的运行:
a.手动方式
(1)将多级包名创建出来 (2)将java文件进行编译,即在dos控制台中的当前目录中使用javac java源文----->生成class字节码文件 (3)将当前字节码文件存储在(1)的包下 (4)带包进行运行:java 包名.类名
b.自动方式
(1)对java文件进行编译: Javac -d .java文件 ----->自动产生class字节码文件 (2)带包进行运行 java 包名.类名
不同包下的编译和运行
(1)将当前类先进行编译:javac -d . Dome.java
(2)将测试类进行编译
pakcage和class中间:import 包名.类名;
Javac -d . 测试类.java
他里面用到Dome类,需要导包,而且必须保证当前类的访问权限足够大
(3)运行 包名.测试类
Java 包名.测试类
内部类:在类A中定义另一个类B,称类B为类A的内部类,类A是他的外部类.
分类:
a.成员内部类:在一个类的成员位置定义的类
特点:成员内部类的成员可以访问外部类的成员,包括私有
在测试类中访问成员内部类(非静态)的成员:
//格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象 class Outer{ //外部类 private int num = 10 ; //外部类成员变量 class Inter{ //内部类 public void method(){ //内部类成员方法 System.out.println(num); } } public void function(){ //外部类成员方法 //创建内部类对象 调用method方法 Inter in = new Inter(); in.method(); } } //测试类 public class Test{ public static void main(String[] args) { //访问内部类的成员 //方法1 创建外部类对象,访问function方法 Outer ou = new Outer(); ou.function(); //方式2 直接访问内部类的成员 Outer.Inter oi = new Outer().new Inter(); oi.method(); } }
成员内部类的修饰符:
private:保证数据的安全性,将内部类隐藏了,被private修饰的无法直接访问,需要通过公共方法访问.
class Outer{//外部类 private class Inter{ //private修饰的内部类 public void method(){ System.out.println("private修饰的内部类的成员方法"); } } public void function(){//外部类的成员方法(公共方法) Inter in = new Inter(); in.method(); } } public class Test{ public static void main(String[] args) { //直接访问,无法访问,报错,被private修饰的只能在本类中访问 //Outer.Inter oi = new Outer().new Inter(); //通过公共方法间接访问 //创建外部类对象 Outer ou = new Outer(); //通过外部类的成员方法访问内部类的成员方法 ou.function(); } }
static:静态的成员内部类中的成员方法(静态/非静态),访问外部类的成员变量都必须是静态的
(1)静态的成员内部类随着外部类的加载而加载
(2)静态的成员内部类中的成员方法的访问
//直接访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名(); //静态访问的另一种方法:外部类名.内部类名.内部类静态方法(); class Outer { //外部类 static int num = 10; //外部类的静态成员变量 int num2 = 20 ; static class Inter { //静态内部类 static void method() { //静态内部类静态成员方法 System.out.println(num); //10 //System.out.println(num2); 无法访问 } public void function(){//静态内部类的非静态成员方法 System.out.println(num); //10 //System.out.println(num2); 无法访问 } } } public class Test{ public static void main(String[] args) { //方法1 直接访问 Outer.Inter oi = new Outer.Inter(); oi.method();//静态方法 oi.function(); //访问静态的另一种方式,通过类名直接访问 //静态的内部类成员方式----->静态的内部类(相当于外部类的静态成员)-->外部类 Outer.Inter.method(); } }
b.局部内部类:在一个类的成员方法中定义的类.
特点:局部内部类可以访问外部类的成员,包括私有成员
class Outer{//外部类 int num = 10 ; //成员变量 private int num2 = 20 ; //被private修饰的成员变量 public void method(){ //外部类的成员方法 class LocalInter{ //局部内部类 public void function(){//局部内部类的成员方法 System.out.println(num); //访问非私有的成员变量 10 System.out.println(num2); //访问私有的成员变量 20 } } //创建局部内部类对象 LocalInter lo = new LocalInter(); lo.function(); } } public class Test{ public static void main(String[] args) { //创建外部类对象 Outer ou = new Outer(); ou.method(); } }
面试题:局部内部类访问局部变量的时候有什么要求?为什么?
要求:把当前的局部变量加入final修饰变成常量.
理由:局部变量的生命周期随着方法的调用而窜在,随着方法的调用结束而消失,但是局部变量还在被局部内部类的成员方法使用,局部类创建的对象不会立即消失,而是等待垃圾回收器空闲的时候回收,所有需要将这个变量变成常量,保证可以一直被访问到.(jdk7以前包含jdk7,局部内部类访问局部变量时,局部变量前必须显示的加入final修饰;jdk8时,jvm做出了内存优化,在局部变量面前自动默认加入了final修饰,省略不写了,可以通过反编译工具查看.)
c.匿名内部类:没有名字的类(重点)
//格式: new 类名/接口名(){ //类名一般都是抽象类 重写抽象方法(){ 共能操作; } };
匿名类的本质:继承了该抽象类或实现了该接口的子类对象.
应用场景:在方法定义中或方法声明上(局部位置使用)
//例如: public 返回值类型 方法名(形式参数){ 业务操作; } //代码实现: interface Person{//定义一个接口 void method(); void method2(); } class Outer{//外部类 public void function(){//外部类成员方法 /*new Person() { //创建匿名内部类访问method()方法 @Override public void method() { System.out.println("方法1"); } @Override public void method2() { System.out.println("方法2"); } }.method(); new Person() { //创建匿名内部类访问method()2方法 @Override public void method() { System.out.println("方法1"); } @Override public void method2() { System.out.println("方法2"); } }.method2();*/ //以上代码调用多个方法需要创建多个匿名内部类,太过于麻烦 //改进:匿名内部类的本质就是实现了该接口的子类对象,因此使用接口多态 Person pe = new Person() { //接口多态,无子实现类名 @Override public void method() { System.out.println("方法1"); } @Override public void method2() { System.out.println("方法2"); } }; pe.method(); //调用method方法 pe.method2();//调用method2方法 } } public class Test{//测试类 public static void main(String[] args) { //创建外部类对象 Outer ou = new Outer(); ou.function(); } } /* (1)形式参数: 抽象类:需要传递当前抽象类的子类对象 接口:需要传递当前接口的子实现类对象 (2)返回值类型: 接口:需要返会当前抽象类的子类对象 抽象类:需要返回当前接口的子是现类对象 无返回值类型(void) */
1.常用类:项目中会大量使用的类或者接口.
集合,String,Date,StringBuffer,线程(Thread)...
2.Object类:Class Object是类Object结构的根,每个类都有Object作为超类,所有对象(包括数组)都实现了这个类的方法
(1)常用的功能:大部分常用类都已经将这些功能重写了
(2)public final Class getClass():表示正在运行的实例!(当前类的字节码文件对象)
(3)public int hashCode():哈希码值,类似于地址值,与哈希码表有关;不同的对象,哈希码值不同
(4)public String gerName():Class类中的成员方法,获取正在运行的类名,表现字符串形式
3.面试题:获取一个类的字节码文件对象的方式有几种?
(1)Object的方法:public final Class getClass()
(2)任意Java类型的class属性
4.Object类的其他功能
(1)public String toString():返回对象的字符串表达形式;创建对象,输出对象名称:打印出来的是对象的地址值,没有意义,建议所有子类覆盖此方法.
class Student{ String name ; int age ; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } //在子类中重写toString()方法 @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } } public class Test{ public static void main(String[] args) { Student s = new Student("章鱼哥",18); //未在子类中重写toString()方法,打印输出 //System.out.println(s); //gj.lass.Student@1540e19d //System.out.println(s.toString()); //gj.lass.Student@1540e19d //直接输出对象名称等价于访问Object类的toString()方法. //在子类中重写toString()方法打印输出 System.out.println(s);//Student{name='章鱼哥', age=18} System.out.println(s.toString());//Student{name='章鱼哥', age=18} } }
(2)public boolean equals(Object obj):指示其他对象与此对象是否相等.
==与equals的区别:
==连接基本数据类型时,比较的是基本数据类型的数据值是否相等;
==连接引用数据类型时,比较的是引用数据类型的地址值是否相等.
equals默认比较的是地址值是否相同;建议子类重写equals方法,来比较他们的内容是否相同.(注意:在重写equals方法的同时,还需要重写hashCode()方法来保证哈希码值必须一样,这样才能比较内容是否相同)
import java.util.Objects; class Student{//所有类都继承了Object类,可以省略不写. String name ; int age ; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } //重写toString()方法 @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } //重写了equals()方法 @Override public boolean equals(Object o) { //比较地址值是否相等 if (this == o) { return true; } //s2对象为空或者两个对象的字节码文件不相同 if (o == null || getClass() != o.getClass()) { return false; } //Object类型向下转型 Student student = (Student) o; //返回s2传进来的对象与this比较的结果,其中equals重写了,比较的是内容 return age == student.age && name.equals(student.name); } //重写了hashCode()方法,当前对象的哈希码值一样才能比较成员信息一样 @Override public int hashCode() { return Objects.hash(name, age); } } public class Test{ public static void main(String[] args) { int a = 1; int b = 1; Student s = new Student("章鱼哥",18); System.out.println(s);//Student{name='章鱼哥', age=18} Student s2= new Student("章鱼哥",18); System.out.println(s2);//Student{name='章鱼哥', age=18} System.out.println(a==b);//基本数据类型比较数据值 true System.out.println(s==s2);//引用数据类型比较的是地址值 flase //子类(Student类)没有重写equals()方法,比较的是地址值 //System.out.println(s.equals(s2)); //false //子类重写了equals()方法与hashCode()方法,比较的是内容 System.out.println(s.equals(s2)); } }
(3)protected Object clone():创建并返回此对象的副本(浅克隆),即复制对象,获取对象的成员.
注意:
a.调用过程中可能存在克隆不支持的异常:throws CloneNotSupportedExceptqion
解决方案:对于jdk提供的类的方法本身存在异常,谁调用这个方法,必须作出处理,否则报错,最简单的方式就是往上抛出异常.
b.受保护的方法无关类中不能访问,需要在当前类中重写clone()方法,需要实现Cloneable接口(标记接口,标记这个类是否能够使用克隆;这个接口没有字段,连方法都没有)
5.Scanner类
Scanner:Java.util的类:文本扫描器
构造方法:
public Scanner(InputStream source)
成员方法:
//判断功能:hasNxetXXX();判断下一个录入数据是否都是XXX类型 public boolean hasNextInt() public boolean hasNextLine() //获取功能:nextXXX() public int nextInt() public String nextLine() ...
注意:
录入数据时可能会出现录入的数据与接受的数据的数据类型不匹配时会产生异常:InputMismatchException.此时久需要用到判断功能来判断录入的数据是否与接受的数据的类型一致.
import java.util.Scanner;//导包 public class Test { public static void main(String[] args) { /*System.in: System类中存在一个标准输入流:in public static final InputStream in InputStream inoutStream = System.in; 字节输入流 */ Scanner sc = new Scanner(System.in); if(sc.hasNextInt()){ //判断功能,判断录入的数据是否是int类型 int num = sc.nextInt(); //获取功能 获取录入的int类型 System.out.println("您输入的第一个数据:"+num); }else if(sc.hasNextLine()){ //判断录入的数据是否是String类型 String str = sc.nextLine();//获取录入的String类型 System.out.println("您输入的第一个数据:"+str); }else{ //录入的数据不合法 System.out.println("很抱歉,您输入的数据不合法,请重新输入."); } } }
6.String类
String的特点:字符串是不变的,他们的值创建后就不能被更改.
String的推荐赋值方式:String 变量名 = "字符串常量" ; String 变量名 = "" ;空字符系列,存在对象,但是是空的.
String类的构造方法:
(1)public String():无参构造
(2)public Stiring(byte[] bytes):将字节数组构造成字符串对象
public class Test{ public static void main(String[] args) { byte[] bytes = {65,66,67,68,78};//创建一个字节数组,静态初始化 String str = new String(bytes);//将字节数组转为字符串对象 System.out.println("str:"+str);//输出字符串 System.out.println("字符串str的长度为:"+str.length());//获取字符串的长度 } }
(3)public String(byte[] bytes,int offset,int length):将一部分字节数组构造成字符串对象
//参数1(byte[] bytes):字节数组对象;参数2(int offset):其实索引;参数3(int length):指定长度 public class Test{ public static void main(String[] args) { byte[] bytes = {65,66,67,68,78};//创建一个字节数组,静态初始化 //将一部分字节数组转为字符串对象,会在ASCLL码表中找到对应的字符 String str = new String(bytes,1,4); System.out.println("str:"+str);//输出字符串 System.out.println("字符串str的长度为:"+str.length());//获取字符串的长度 } }
(4)public String(char[] vale):将字符数组构造成字符串
public class Test{ public static void main(String[] args) { byte[] bytes = {'h','e','l','l','o'};//创建一个字符数组,静态初始化 String str = new String(bytes);//将字符数组转为字符串对象 System.out.println("str:"+str);//输出字符串 System.out.println("字符串str的长度为:"+str.length());//获取字符串的长度 } }
(5)public String(char[] vale,int offset ,int count):将一部分字符数组构造成字符串对象
public class Test{ public static void main(String[] args) { byte[] bytes = {'h','e','l','l','o'};//创建一个字符数组,静态初始化 String str = new String(bytes,1,4);//将一部分字符数组转为字符串对象 System.out.println("str:"+str);//输出字符串 System.out.println("字符串str的长度为:"+str.length());//获取字符串的长度 } }
(6)public String(String original):创建一个字符串对象,里面存储字符串常量
public class Test{ public static void main(String[] args) { String str = new String("hello");//创建一个字符串对象,存储字符串常量 System.out.println("str:"+str);//输出字符串 System.out.println(str.length());//获取字符串长度 } }
面试题:String s = "hello" ; 和String s2 = new String("hello") ;两者有什么区别?分别创建了几个对象?
共同点:都是在创建一个字符串对象"hello"
不同点:内存执行不一样:
前者:在常量池中开辟空间,创建了一个对象,节省了内存
后者:在堆中开辟空间,而且里面存在常量,常量池会标记,它创建了两个对象.
String类的获取功能:
(1)public char charAt(int index):获取指定索引处的字符值
public class Test{ public static void main(String[] args) { String str = "hello" ; char ch = str.charAt(2);//返回指定位置的索引值 System.out.println(ch);//输出该索引值处的字符 } }
(2)punlic String concat(String str):拼接功能,拼接心得字符串
public class Test{ public static void main(String[] args) { String str = "hello" ; //拼接功能,将"hello" "world" "!"拼接成一个新的字符串 String sc = str.concat("world").concat("!"); System.out.println(sc);//输出拼接后的字符串 } }
(3)public int indexOf(int ch):返回指定字符第一次出现的索引值
public class Test{ public static void main(String[] args) { String str = "hellojavaee" ; int index = str.indexOf("e");//返回字符'e'第一次出现的索引值 System.out.println(index);//输出索引值 } }
(4)public int lastIndexOf(int ch):返回指定字符最后一次出现的索引值
public class Test{ public static void main(String[] args) { String str = "hellojavaee" ; int index = str.lastIndexOf("e");//返回字符'e'最后一次出现的索引值 System.out.println(index);//输出这个索引值 } }
(5)public int length():获取字符串长度
public class Test{ public static void main(String[] args) { String str = "hellojavaee" ; int length = str.length();//返回字符串的长度 System.out.println(length);//输出字符串的长度 } }
(6)public String[] split(String regex):字符串的拆分方法,返回字符串数组
public class Test{ public static void main(String[] args) { String str = "h-e-l-l-o-j-a-v-a-e-e" ; String[] arr = str.split("-");//将字符串拆分,返回字符串数组 System.out.print("["); for(int i = 0 ; i < arr.length ; i++){//遍历返回的字符串数组 if(i==arr.length-1){ System.out.println(arr[i]+"]"); }else{ System.out.print(arr[i]+", "); } } } }
String类的截取功能:
(1)public String substring(int beginIndex):字符串截取功能,默认从beginIndex起始索引截取到末尾
public class Test{ public static void main(String[] args) { String str = "helloworld" ; String str1 = str.substring(4);//从索引值为4的地方开始截取到末尾,返回一个字符串 System.out.println(str1);//输出截取后获得的新字符串 } }
(2)public String substring(int beginIndex , int endIndex):从指定位置开始截取到指定位置结束(包前不包后)
public class Test{ public static void main(String[] args) { String str = "helloworld" ; //从索引值为4的地方开始截取到索引值为8的位置之前,不包含索引值为8的字符,返回一个字符串 String str1 = str.substring(4,8); System.out.println(str1);//输出截取后获得的新字符串 } }
String的转换功能:
(1)public char[] toCharArray():将字符串转换为字符数组
p
ublic class Test{ public static void main(String[] args) { String str = "helloworld" ; char[] arr = str.toCharArray();//将字符串转换为字符数组 System.out.print("["); for(int i = 0 ; i < arr.length ; i++){//遍历返回的字符数组 if(i==arr.length-1){ System.out.println(arr[i]+"]"); }else{ System.out.print(arr[i]+", "); } } //需要查看数组的内容:使用数组工具Arrays // static String toString(任意数组类型):静态功能,将任意类型的数组转换成字符串形式 System.out.println(Arrays.toString(arr)); } }
(2)public byte[] getBytes():使用平台的默认字符集进行编码过程,将字符串转换为字节数组
public class Test{ public static void main(String[] args) { String str = "helloworld" ; //将字符串转换为字节数组,会在ASCLL码表中找到相应的字节 byte[] arr = str.getBytes(); //需要查看数组的内容:使用数组工具Arrays System.out.println(Arrays.toString(arr)); } }
(3)public byte[] getBytes(String charset):使用指定的字符集进行编码"GBK/UTF-8"
编码:将能看得懂的字符串转换成看不懂的字节
解码:将看不懂的字节转换成看得懂的字符串
(4)public String toLowerCase():将字符串中的每一个字符转换成小写
public class Test{ public static void main(String[] args) { String str = "HELLOWORLD" ; //将字符串中的每一个字符转换成小写 String str1 = str.toLowerCase(); System.out.println(str1);//helloworld } }
(5)public String toUpperCase():将字符串中的每一个字符转换成大写
public class Test{ public static void main(String[] args) { String str = "helloworld" ; //将字符串中的每一个字符转换成大写 String str1 = str.toUpperCase(); System.out.println(str1);//HELLOWORLD } }
(6)万能方法:public String valueOf(boolean/float/long/double/...Object):将任意的数据类型转换成String(静态功能)
public class Test{ public static void main(String[] args) { int num = 100 ; //将int类型的num准换成String String str = String.valueOf(num); System.out.println(str);//输出的是一个字符串:100 } }
String类的判断功能:
(1)public boolean cotains(String s):判断是否包含子字符串
(2)public boolean startsWith(String prefix):判断是否以指定字符串开头
(3)public boolean endsWith(String suffix):判断是否以指定字符串结尾
(4)public boolean equals(Object anObject):判断字符串内容是否相等,区分大小写
(5)public boolean equalslgnoreCase(String anotherString):判断字符串内容是否相等,忽略大小写
(6)public boolean isEmpty():判断字符串是否为空
public class Test{ public static void main(String[] args) { String str = "HelloJavaEE" ; String str1 = "HelloJavaEE" ; String str2 = "helloJavaEe"; boolean flag = str.contains("llo");//判断是否包含字符串"llo" System.out.println(flag);//true boolean flag1 = str.startsWith("Hel");//判断是否以字符串"Hel"开头 System.out.println(flag1);//true boolean flag2 = str.endsWith("aEE");//判断是否以字符串"aEE"结尾 System.out.println(flag2);//true boolean flag3 = str.equals(str1);//判断内容是否相等,区分大小写 System.out.println(flag3);//true boolean flag4 = str.equalsIgnoreCase(str1);//判断内容是否相等,不区分大小写 boolean flag5 = str.equalsIgnoreCase(str2);//判断内容是否相等,不区分大小写 System.out.println(flag4);//true System.out.println(flag5);//true boolean flag6 = str.isEmpty();//判断字符串是否为空 System.out.println(flag6);//false } }
String类的其他功能:
(1)public String replace(char oldChar,char newChar):用新的字符将旧的字符替换掉
(2)public String replace(String oldChar,String newChar):用新的字符串将旧的字符串去掉
(3)public String replaceAll(String regex,String replacement):使用指定的replacement替换字符内容
(4)public String trim():去除字符串前后两端的空格
public class Test{ public static void main(String[] args) { String str = "HelloJavaEE" ; String str1 = " HelloJavaEE " ; //用新的字符把旧的字符替换掉 String newStr1 = str.replace('e', 'o'); System.out.println(newStr1);//HolloJavaEE //用新的字符串替换旧的字符串 String newStr2 = str.replace("EE", "SE"); System.out.println(newStr2);//HelloJavaSE boolean newStr3 = str1.isEmpty();//去掉字符串前后两端的空格 System.out.println(newStr3);//HelloJavaEE } }
面试题:
public int compareTo(String anotherString) 如何进行比较?
String s1 = "hel"; 与 String s2 = "hello";进行字典比较结果为多少?为什么?
6.StringBuffer类
StringBuffer:简称"字符串缓冲",线程安全的,且可变的字符序列
线程:
单线程:程序的执行路径只有一条,不考虑安全性,只考虑效率!
多线程:程序的执行路径有多条,考虑安全性,效率问题不是重点.
StringBuffer和StringBuilder有什么区别?
共同点:两者都是字符串区,支持可变的字符序列,而且都有相同的API
不同点:前者是线程安全的类,安全(同步),但是执行效率低;后者是线程不安全的类,不同步,执行效率高.
获取字符缓冲区长度的方法:public int length();
获取字符串缓冲区容量大小的方法:public int capaaity()
StringBuffer的构造方法:
(1)StringBuffer():无参构造方法
(2)StringBuffer(int capacity):指定容量大小的字符串缓冲序列
(3)StringBuffer(String str):指定缓冲区的具体内容str,容量大小=16个默认容量+当前字符串长度
StringBuffer类的添加和删除功能:
(1)StringBuffer append(任何数据类型):将任何数据类型的元素最加到字符序列中(字符串缓存区)
(2)StringBuffer insert(int offset , String str):在指定位置插入元素
(3)public StringBuffer deleteCharAt(int index):在指定位置删除字符,返回字符串缓冲区本身
(4)public StringBuffer delete(int start,int end):删除从指定位置到end-1处的字符
public class Test{ public static void main(String[] args) { StringBuffer sb = new StringBuffer(); //:将任何数据类型的元素最加到字符序列中(字符串缓存区) sb.append(2); sb.append('A'); sb.append("helloworld"); System.out.println(sb);//2Ahelloworld //在指定位置插入元素 sb.insert(2,'a'); System.out.println(sb);//2Aahelloworld //在指定位置删除字符,返回字符串缓冲区本身 sb.deleteCharAt(5); System.out.println(sb);//2Aaheloworld //删除从指定位置到end-1处的字符 sb.delete(6,9); System.out.println(sb);//2Aahelrld } }
StringBuffer类的反转功能:
public StringBuffer reverse():反转功能
public class Test{ public static void main(String[] args) { String str = "hello" ;//创建一个字符串 StringBuffer sb = new StringBuffer(str) ;//转换为StringBuffer类型 StringBuffer reverseStr = sb.reverse();//反转 System.out.println(reverseStr);//olleh } }
7.Integer类
Integer:包装一个对象中的原始类型int的值
(1)public static String toBinaryString(int i):将整数类型转换位字符串形式的二进制
(2)public static String toOctalString(int i):将整数类型转换位字符串形式的八进制
(3)public static String toHexString(int i):将整数类型转换位字符串形式的十六进制
构造方法:
(1)Integer(int value):将int类型构造成Integer类型
(2)Integer(String s) throws NumberFormatException:将Sting类型构造成Integer类型,但是前提必须是数字字符串.