赞
踩
现实世界事物描述:一个事物体现出的的不同形态! (内存中) 水这个事物: 液态,固态,气态 从程序中描述:这个对象在内存中的变化 猫是猫 :Cat c = new Cat() ; 猫是动物 :Animal a = new Cat() ;
1)必须存在继承关系, 如果没有继承,谈不了多态! (继承的好处第三点) 2)必须存在方法重写,需要让子类完成自己的业务功能,需要将父类的某些功能进行覆盖(重写) 举例: 动物都需要吃 只要见到具体动物----才知道吃什么 ,具体的动物的子类将"吃"的功能进行重写 3)需要存在"父类引用指向子类对象" 格式: Fu fu =new Zi() ; 父类名 对象名 = new 子类名() ; "向上转型"(使用的是父类的东西)
成员变量: 编译看左,运行看左! (如果编译通过了,说明Fu中存在变量,运行看左,使用父类的东西) 成员方法:(非静态的) 编译看左,运行看右(因为子类出现了父类一模一样的方法声明,覆盖了) 静态的成员方法:算不上方法重写.和类相关的.称为"类成员" 编译看左,运行看左! 随着类的加载而加载,访问通过类名访问 构造方法: 因为存在继承关系,存在无参构造/有参构造,都需要父类先初始化,然后才是子类,分层初始化
//举例: //父类 class Fu{ int num = 10 ; public void show(){ System.out.println("show Fu") ; } public static void method(){ System.out.println("method Fu..."); } public Fu(){ System.out.println("Fu..."); } } class Zi extends Fu{ int num = 20 ; //重写了 @Override public void show() { System.out.println("show Zi") ; } public static void method(){ System.out.println("method Zi..."); } public Zi(){ System.out.println("Zi"); } } public class DuoTaiDemo { public static void main(String[] args) { //需要存在"父类引用指向子类对象" Fu fu = new Zi() ; //父类的引用fu---堆内存中创建的它的子类对象 //访问成员变量 System.out.println(fu.num) ; fu.show() ; // fu.method() ; //静态方法推荐方式: /* Fu.method() ; Zi.method();*/ } }
1)可以提高代码的复用性(继承保证的) 2)可以提高代码的扩展性(由多态的保证:Fu fu = new Zi() 父类引用指向子类对象)
多态的在使用过程中,存在向上转型和向下转型, 向下转型使用不当,会出现问题: java.lang.ClassCastException:类转换异常: 属于 "运行时期异常"----->代码不严谨导致的
//举例: //定义动物类 class Animal{ public void eat(){ System.out.println("动物都需吃饭..."); } } //猫 class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼..."); } } //狗 class Dog extends Animal{ @Override public void eat() { System.out.println("狗吃骨头..."); } } //测试类 public class DuoTaiDemo { public static void main(String[] args) { //父类引用指向子类对象:向上转型 Animal a = new Cat() ; //猫是动物 a.eat() ; //还原成猫--向下转型 Cat c = (Cat) a; //堆内存是猫: 猫是猫 c.eat() ; //创建一只狗:父类引用指向其他子类对象 a = new Dog() ; //狗是动物 :堆内存是狗对象 a.eat(); //还原成狗--向下转型 Dog d = (Dog) a; //堆内存是还狗对象,狗是狗 d.eat(); System.out.println("--------------------------------------------") ; //Cat cc = (Cat) a; //符号向下转型格式(强转格式)//java.lang.ClassCastException: com.qf.duotai_03.Dog cannot be cast to com.qf.duotai_03.Cat } }
*什么是抽象? 在现实事物中,将比较概括性的事物统称为"抽象的事物" 猫和狗是具体的动物了,他们都继承自动物类,将动物就可以看成是一个抽象的事物; 猫和狗具体的功能应该具体体现,在动物事物中,应该给出一个声明即可,不需要具体体现! *抽象类: abstract class 类名{} *抽象类的注意事项: 1)在一个类中,如果当前类中存在抽象功能(方法),那么这个类必须抽象类; 2)一个抽象类中,不一定都都是抽象方法; *抽象方法:没有方法体的一个成员方法,并且携带一个关键字 abstract 权限修饰符 abstract 返回值类型 方法名(形式参数列表) ; 3)抽象类的子类: 为抽象类:一定会存在具体的子类,否则没有意义! 为具体类:它才有意义,可以创建实例! 4)抽象类的本质: 强制子类必须完成的事情! *抽象类特点:不能实例化 (不能创建对象)
成员变量: 既可以是变量,也可以是常量! 成员方法: 既可以是抽象方法,也可以是非抽象方法 构造方法: 存在无参/有参:分层初始化 目的:对数据进行初始化!
private: 被private修饰的方法只能在本类访问;有一个abstract关键字:强制子类重写 final: 被final修饰的成员方法,不能被重写;而abstract强制子类重写 static: 被static修饰符的方法,需要被类名访问,随着类的加载而加载;而abstract需要让子类重写这个方法,通过对象名来访问(访问时机冲突) 方法重写的注意事项: 子类继承父类:重写父类的方法的时候,访问权限不能更低,跟父类的权限保持一致,否则报错!
例题:一个类如果没有抽象方法,那么将这个类定义为抽象类有什么意义呢? 意义:就是为了不让外界new对象,不能实例化. 抽象类特点:不能实例化 (如何实例化,通过抽象类多态实例化:具体的子类)这个类没有抽象方法,将它定义为抽象类.
1)接口实际就是描述事物本身之外的"额外功能(扩展功能)" 举例1: 猫和狗事物,能够去"跳高",跳高这个动作本身并不是这些事物本身具备的功能,它们经过驯养员的特殊培训就可以具备 "跳高","做计算","钻火圈", 这个功能 "额外功能",谁能够将接口中的额外功能实现了,就具备这个功能! 举例2: 电脑上的USB接口----->插上不同设备,电脑可以完成不同的动作:数据传输,打字,玩游戏,.... 2)格式: 关键字interface 接口名{} ---- 接口的命名规则和类一样,"大驼峰命名法" 3)接口如何实现: 接口是比抽象类还抽象的一种概念! 接口的子类------>子实现类 (接口和实现类: 实现关系 : implements) 4)注意事项: 1)接口的子类可能是抽象类,那么肯定会存在最具体的子类,否则没有意义! 2)具体类:就通过接口多态进行实例化! 接口名的 对象名 = new 子实现类名() ; 开发中"接口和子实现类的定义名称的规则": 定义接口名之后,在定义子实现类的时候,名称都会在接口名的后面+Impl
//举例: //设计一个台灯类(Lamp)其中台灯有灯泡类(Buble)这个属性,还有开灯(on)这个方法。 //设计一个灯泡类(Buble)(抽象类),灯泡类有发亮的方法(shine),其中有红灯泡类(RedBuble)和绿灯泡类(GreenBuble) //他们都继承灯泡类(Buble)一个发亮的方法。 设计完成后进行测试 public abstract class Buble { //给发亮的方法声明 public abstract void shine() ; } public class GreenBuble extends Buble { @Override public void shine() { System.out.println("灯泡可以发绿光..."); } } public class RedBuble extends Buble { @Override public void shine() { System.out.println("灯泡可以发红光..."); } } //台灯类(Lamp) public class Lamp { //灯泡类(Buble private Buble buble ; //台灯开灯,造成灯泡发亮 public void on(Buble buble) {//形式参数是引用类型---->抽象类:实际需要当前抽象类的子类对象:抽象类多态 buble.shine(); } } public class Test { public static void main(String[] args) { //抽象类多态测试 Lamp lamp = new Lamp() ; Buble buble = new RedBuble() ; lamp.on(buble) ; buble = new GreenBuble() ; lamp.on(buble); } }
成员变量:只能是常量:存在默认修饰符public static final 可以省略不写; 成员方法:只能是抽象方法:存在默认修饰符 public abstract 可以省略不写; 构造方法:接口没有构造方法,因为接口只是为了提供事物的额外功能,谁实现了接口,就具备这个功能!
1)成员区别 接口: 成员变量:只能是常量,存在默认修饰符 public static final 可以省略 成员方法:只能是抽象方法,存在默认修饰符 public abstract 可以省略 构造方法:接口没有 抽象类: 成员变量:即可以是常量,也可以是变量 成员方法:既可以存在抽象方法,而且抽象方法abstract不能省略,也可以存在非抽象方法 构造方法:存在:无参/有参,继承关系,先让父类初始化,然后在是子类初始化(分层初始化) 2)关系的区别 类与类之间关系:继承关系 extends, 只支持单继承,不支持多继承,但可以多层继承 类与接口之间的关系:实现关系 implements, 一个类继承另一个类的同时,可以实现多个接口 接口与接口之间关系:继承关系 extends, 不仅支持单继承,也可以多继承,也可以多层继承 3)设计理念的区别 抽象类----存在继承关系extends, 继承体现的是"is a"的关系 接口----->存在实现关系implements,仅仅是将额外功能提供相关的事物,这个事物要具备额外功能 必须实现这个接口, 体现的是一种"like a"的关系
方法的形式参数可以是基本数据类型:实际参数需要传递当前具体的基本类型的数据值即可. 方法的形式参数是引用数据类型: 类: 具体类: 调用该方法,实际参数需要传递的是当前具体类对象 抽象类: 调用该方法,实际参数需要传递的是当前抽象类的子类对象,抽象类多态完成! 接口:调用该方法,实际参数需要传递的是当前接口的子实现类对象:接口多态
//举例: //定义一个接口 interface Love{ void love() ; } //类 class LoveDemo{ public void function(Love love){//方法的形式参数是引用类型:接口, //调用该方法,实际参数需要传的是当前接口的子实现类对象:接口多态 love.love() ; } } //子实现类 class LoveImpl implements Love{ @Override public void love() { System.out.println("爱生活,爱Java"); } } //测试类 public class ArgsDemo3 { public static void main(String[] args) { //需求:调用LoveDemo类中的function LoveDemo ld = new LoveDemo() ; //Love lo = new Love() ;//接口不能实例化 Love lo = new LoveImpl() ; //接口多态 ld.function(lo) ; System.out.println("------------------------") ; //匿名对象 new LoveDemo().function(new LoveImpl()); } }
instanceof:判断 格式: 对象名称 instanceOf 类名 功能: 判断当前对象名是否当前类的实例 (原码里面经常看到instanceOf)
方法的返回值类型: 基本数据类型:简单,最终通过功能的业务操作,返回的数据结果 举例: public int sum(int a,int b){} 引用数据类型(重点) 类: 具体类:如果一个方法的返回值是一个具体类,那么该方法就需要返回当前类具体对象! 抽象类:如果一个方法的返回值是一个抽象类型,那么该方法需要返回当前抽象类的子类对象,抽象类多态! 接口 :如果一个方法的返回值是接口类型,那么该方法需要返回的是当前接口的子实现类对象,接口多态!
//举例: interface Love{ void love() ; } class LoveDemo{ public Love function(){//方法的返回值是一个接口类型,接口不能实例化,需要返回的当前接口的子实现类对象 //? //方式1: //接口多态 // Love love = new LoveImpl() ; // return love ; //匿名对象 return new LoveImpl() ; } } //定义子实现类 class LoveImpl implements Love{ @Override public void love() { System.out.println("love loveImpl..."); } } //测试类 public class ReturnDemo3 { public static void main(String[] args) { //测试调用:LoveDemo中的function方法: LoveDemo loveDemo =new LoveDemo() ; Love love = loveDemo.function(); love.love(); } }
在同一个包下的当前类中 在同一个包下的子类中/无关类 在不同包下的子类中 在不同包下的无关类中 private Y 默认修饰符 Y Y protected:受保护的 Y Y Y public Y Y Y Y 四个权限修饰符的优先级: 从大到小---> public > protected > 默认修饰符 > private
包:package---目录(文件夹)的意思 开发中:都使用的多级包中间.隔开 真实开发场景中:包的命名规则 多级包:都是公司域名反写 istone.net.dev.xx 通过包名------->区分代码的层次结构的!
8.1.1 在同一包下的编译和运行
首先:创建package包名(推荐多级包:中间点隔开,分包) 两种情况: 1)手动方式: a)将你当前的多级包名创建出来 b)先将当前的Java文件进行编译 在当前目录中:使用javac java源文件 ---->.class文件 c)将当前字节码文件存储在刚才1)包下 d)带包进行运行 java 包名.类名 D:\EE_2110\day15\code\01_同一个包下的编译和运行>javac Demo.java D:\EE_2110\day15\code\01_同一个包下的编译和运行>java com.qf.Demo demo... D:\EE_2110\day15\code\01_同一个包下的编译和运行> 2)自动方式: a)对Java文件进行编译 javac -d . 某个Java文件 ---->自动的产生包名和字节码文件 b)带包进行运行 java 包名.类名 D:\EE_2110\day15\code\01_同一个包下的编译和运行>javac -d . Demo.java D:\EE_2110\day15\code\01_同一个包下的编译和运行>java com.qf.Demo demo... D:\EE_2110\day15\code\01_同一个包下的编译和运行>
8.1.2 在不同包下的编译和运行
在不同包下的编译和运行 直接使用自动方式 1)将当前Demo类先进行编译 javac -d . Demo.java 2)将Test类进行编译 pakcage和class中间:import 包名.类名; javac -d . Test.java--- 它里面用到Demo类,需要导包,而且必须保证当前类的访问权限足够大 3)运行 com.qf.Test类 java com.qf.Test
9.1 什么是内部类?
在一个类A中定义另一个类B,那么将类B就称为类A的内部类; 类A是它的外部类!
9.2 内部类
成员内部类:在一个类的成员位置定义的
局部内部类:在一个类的成员方法中定义的类
1) 成员内部类 :在一个类的成员位置定义的 特点:成员内部类(非静态)的成员可以访问外部类的成员,包括私有! 在测试类中: 如何直接访问成员内部类的成员---此时该成员内部类:非静态 固定格式: 外部类名.内部类名 对象名 = 外部类对象.内部类对象 ; //外部类 class Outer2{ //外部类的成员变量 private int num = 100 ; //成员内部类 class Inner2{ //成员方法 public void show(){ System.out.println(num) ; } } //定义外部类的成员方法:访问内部类的成员 public void method(){ //show() ;不能这样写 //访问Inner2成员内部类的成员:---->通过对象方法 Inner2 inner = new Inner2() ; inner.show() ; } } //测试类 public class InnerClassDemo2 { public static void main(String[] args) { //创建外部类对象,访问它的method方法 /* Outer2 o = new Outer2() ; o.method() ;*/ //直接访问 // 外部类名.内部类名 对象名 = 外部类对象.内部类对象; Outer2.Inner2 oi = new Outer2().new Inner2() ; oi.show() ; } }
2) 成员内部类中的修饰符: 可以private,static 2.1) private: 保证数据安全性(将内部类隐藏了) 举例:身体内有心脏; 伪代码: class Body{ //成员内部类 private class Heart{ //成员方法 //并不是所有的人都可以直接完成这个完成手术---不安全! public void operator(){ System.out.println("心脏出问题了,需要做心脏搭桥手术...") ; } } } //测试类中直接访问Heart里面operartor 外部类名.内部类名 对象名 = 外部类对象.内部类对象; //Body.Heart bh = new Body().new Heart() ; // bh .operator() ; 2.2) 成员内部类里面还可能存在静态修饰符static 静态的成员内部类中的成员方法(静态的还是非静态),访问外部类的成员变量,都必须是静态的 1.静态的成员内部类随着外部类的加载而加载; 2.如何直接访问静态的成员内部类的中成员方法 外部类名.内部类名 对象名 = new 外部类名.内部类名() ; //定义外部类 class Outer3{ public int num = 100 ; public static int num2 = 200 ; //成员内部类---加入static static class Inner3{//类都已经是静态的了 //里面有一个非静态方法 public void show(){ // System.out.println(num) ; System.out.println(num2) ; } //静态方法 public static void show2(){ //System.out.println(num) ; System.out.println(num2) ; } } } //测试类 public class InnerClassDemo3 { public static void main(String[] args) { //外部类名.内部类名 对象名 = 外部类对象.内部类对象; // Outer3.Inner3 oi = new Outer3().new Inner3() ; //用不了了:只能针对非静态的成员内部类 //成员内部类是静态的------将它可以看成是"外部类的静态成员" // 外部类名.内部类名 对象名 = new 外部类名.内部类名() ; Outer3.Inner3 oi =new Outer3.Inner3() ; oi.show() ; oi.show2() ;//静态方法 System.out.println("--------------------------------------") ; //show2()的另一种方式 //成员内部类是静态的------将它可以看成是"外部类的静态成员"而且静态的成员内部类中静态 // 的成员方法 Outer3.Inner3.show2() ; //静态的成员内部类的静态成员方法(推荐这种访问) } }
3) 局部内部类的也是内部类的一种 特点: 局部内部类可以访问外部类的成员吗? 可以,包括私有; 面试题: 局部内部类访问局部变量的时候,有什么要求?为什么? 要求当前的局部变量为常量:加入final修饰 ,为什么? jdk8 jvm已经做了内存优化:通过反编译工具查看:num2:自动带上final修饰(默认,省略了) jdk7以前(包含jdk7):局部内部类访问局部变量,前面必须显示的加入final修饰 局部变量的生命周期随着方法的调用而存在,随着方法调用结束而消失; 但是局部变量还在被局部内部类的成员方法在使用,局部类的对象不会立即消失,需要等待GC回收,需要将这个变量变成 常量,保证一直可以访问到! //外部类 class Outer{ private int num = 20 ; // private int num2 = 50 ;//私有 //成员方法 public void method(){ //局部变量 final int num2 = 100 ; //jdk8 jvm已经做了内存优化:通过反编译工具查看:num2:自动带上final修饰(可以省略:优化过了) //定义局部内部类 class Inner{ //成员方法 public void show(){ //访问局部变量num3 System.out.println(num) ; System.out.println(num2) ; //还在使用变量num2 // System.out.println(num2) ; } } //外部类的当前这个成员方法中:创建局部内部类对象,调用show Inner inner = new Inner() ; inner.show(); } } //测试类 public class InnerClassDemo1 { public static void main(String[] args) { //创建外部类对象 Outer outer = new Outer() ; outer.method() ; } }
9.3 匿名内部类
内部类的另一种格式:(重点) 匿名内部类:没有名字的类 格式: new 类名/接口名(){ 一般类名--->抽象类 重写抽象方法(){ 业务功能; } } ; 匿名内部类的本质: 就是继承了该抽象类或者实现了该接口子类对象; 应用场景: 匿名内部类的使用在方法定义中或者是方法声明上:局部位置中使用 public void show(抽象类名 参数名){ } 1)可能方法的形式参数是一个接口/抽象类 2)可能方法返回值类型时一个接口/抽象类 //定义一个接口 interface Inter{ //只有一个抽象方法 void show() ; //多个抽象方法 void show2() ; } //定义一个外部类 class Outer{ //有一个成员方法 public void method(){ //局部位置 //方法体中:需要将Inter接口中的show进行重写 /*class Inner implements Inter{ //局部内部类的类名Inner @Override public void show() { } }*/ /** * 匿名内部类的格式 * new 类名/接口名(){ 一般类名--->抽象类 * 重写抽象方法(){ * 业务功能; * } * } ; */ /* new Inter(){ @Override public void show() { System.out.println("show Inter..."); } //重写接口中的方法 @Override public void show2() { System.out.println("show2 Inter..."); } }.show() ; new Inter(){ @Override public void show() { System.out.println("show Inter..."); } //重写接口中的方法 @Override public void show2() { System.out.println("show2 Inter..."); } }.show2() ;*/ //问题:当接口中的抽象方法越来越多,此时使用匿名内部类的时候,调用方法很麻烦... //优化:如果能够为当前匿名内部类(表示是继承了抽象类或者实现了接口的子类对象),给他起个对象名称 Inter inter = new Inter() {//还是接口多态方式:不过子实现类没类名 @Override public void show() { System.out.println("show Inter..."); } @Override public void show2() { System.out.println("show2 Integer..."); } }; inter.show() ; inter.show2() ; } } //测试类 public class NoNameInnerClassDemo { public static void main(String[] args) { //创建外部类对象 Outer outer = new Outer() ; outer.method() ; } }
常用类: JavaSE---->JavaEE:做项目中会使用大量的写Java中常使用的接口或者类 举例: 集合 String Date日期 StringBuffer 线程Thread IO流程:InputStram/OutputStream:数据传输 网络编程 反射 必须知道常用类或者接口中常用的功能(方法),并且熟练使用! *需要使用jdk的API查询:应用程序接口文档 *后期不断的去使用第三方的API(阿里的,腾讯,百度...)
java.lang.Object是类Object结构的根。每个类都有Object作为超类(父类) 常用的功能:大部分常用类已经将这些功能重写了 public final Class getClass():表示正在运行的类的实例! (当前类的字节码文件对象)(重点) public int hashCode():哈希码值,把它可以看成是一个"地址值",不是真实意义的地址值,和哈希表有关!(了解) 不同的对象,哈希码值不同 Class---->后期反射中讲 成员方法: public String getName():获取当前正在运行的的类名,表现字符串形式 面试题: 获取一个类的字节码文件对象的方式有几种? 1)Object的方法 public final Class getClass() 2)任意Java类型的class属性 public class ObjectDemo { public static void main(String[] args) { // Demo demo = new Demo() ; // System.out.println(demo.getClass()) ; //创建两个学生对象 Student s1 = new Student() ; Student s2 = new Student() ; //System.out.println(s1) ; //System.out.println(s2) ; Class c1 = s1.getClass() ; Class c2 = s2.getClass() ; System.out.println("----------------------------------------"); // public String getName() String name1 = c1.getName(); String name2 = c2.getName(); System.out.println(name1+"----"+name2); System.out.println(c1) ;//包名.类名 System.out.println(c2) ; System.out.println(s1==s2) ;//分别需要开辟空间 System.out.println(c1==c2) ; //因为类就加载一次,产生的字节码文件就一个 System.out.println("----------------------------------") ; //另一种方式也可以获取字节码文件对象 //任意Java类型的class属性(自定义的类/jdk提供类) Class c3 = Student.class ; System.out.println(c3); System.out.println(c3==c2); System.out.println("----------------------------------------------------------------") ; int i = s1.hashCode(); int i2 = s2.hashCode(); System.out.println(i); System.out.println(i2); System.out.println("高".hashCode()) ; System.out.println("张".hashCode()); } }
10.1 Object的toString方法
public String toString()返回对象的字符串表示形式;应该是一个简明扼要的表达,容易让人阅读 Object 的toString 方法:获取的是某个对象的地址值,地址值没有意义 创建对象,输出对象名称:打印出来的对象的地址值,没有意义; 让所有子类覆盖toStrin此方法。打印出来应该看到的是当前这个对象的成员信息表达式!! Integer类 int类型包装类类型 静态功能: public static String toHexString(int code) public class ObjectDemo { public static void main(String[] args) { //创建一个学生对象 Student s = new Student("刘德华",48) ; // System.out.println(s) ;//com.qf.object_01.Student@1540e19d:地址值没有意义 //直接输出对象名称:等价于 访问其实就是Object类toString()方法 // System.out.println(s.toString());//com.qf.object_01.Student@1540e19d /* *Object类的toString * public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } * */ // String name = s.getClass().getName(); // System.out.println(name+"@"+Integer.toHexString(s.hashCode()));//com.qf.object_01.Student System.out.println(s ); System.out.println(s.toString()); //类似于Object obj = new Student() ; /* String str = new String() ; System.out.println(str);*/ } }
10.2 Object的equals方法
public boolean equals(Object obj):指示其他对象与此对象是否"相等" ==和equals的区别: ==:连接的是基本数据类型:比较的基本数据类型数据值是否相等 int a= 10 ; int b = 20 ; a==b ; ==:连接的是引用数据类型,比较的是引用数据类型的地址值是否相同 equals:默认比较的是地址值是否相同,建议子类重写equals方法,比较他们内容是否相同(成员信息是否相同)!!! 在重写equals方法的同时,还需要重写hashCode()方法,保证哈希码值必须一样,才能比较equals alt+ins--->equals and hashCode 如果重写Object类的equals方法之后,都是比较的内容是否相同(成员信息是否相同) 大部分的常用类都会重写Object类的equals方法 public class ObjectDemo { public static void main(String[] args) { Student s1 = new Student("高圆圆",42) ; System.out.println(s1) ; Student s2 = new Student("高圆圆",42) ; System.out.println(s2); System.out.println(s1==s2) ;//false System.out.println("----------------------------------------") ; //public boolean equals(Object obj) System.out.println(s1.equals(s2)) ;//false:Student类没有重写equals //true:因为重写了Object的equals方法 /* Object的equals方法的原码 public boolean equals(Object obj) {//多态:new Student() ; return (this == obj);//s1 s2 :两个对象的== :默认比较的是地址值是否相同 } */ //System.out.println("高圆圆".hashCode()); /* @Override public boolean equals(Object o) { if (this == o) { //比较是地址值是否相同 return true; } if (o == null || getClass() != o.getClass()) { //s2对象如果为null,或者是当前两个对象的字节码文件不相同 return false; } Student student = (Student) o; //----Object类型:向下转型 if (age != student.age){ //this.age !=student.age :和s2对象进行比较年龄是否相同 return false; } return name.equals(student.name); //this.name 和传进来对象的姓名比较 name类型:String类型:String类型底层重写Object的equals方法 :由于重写了,所以String类型里面 equals:比较的是字符串的内容是相同 } */ } }
10.3 Object的clone方法
protected Object clone() throws CloneNotSupportedException:调用过程中可能存在克隆不支持的异常 对于jdk提供的类的方法本身存在异常.谁调用这个方法,必须做出处理,否则报错,最简单的方式继续往上抛 throws 创建并返回此对象的副本(浅克隆):了解 简单理解:复制对象,获取对象的成员... public class ObjectDemo { public static void main(String[] args) throws CloneNotSupportedException { //之前的写法 Student s1 = new Student("高圆圆",42) ; System.out.println(s1) ;//直接输出对象名称,等价于调用自己的toString() System.out.println(s1.getName()+"---"+s1.getAge()) ; //定义一个变量 Student s2 = s1 ; System.out.println(s2.getName()+"---"+s2.getAge()) ; System.out.println("-----------------------------------------") ; //现在使用clone]方法:浅克隆 Object object = s1.clone() ;//受保护的方法,无关类中不能访问...需要在当前子类中重写clone方法,需要实现Cloneable接口 //上面的写法:类似于Object object = new Student() ; //向下转型 Student s3 = (Student) object ; System.out.println(s3.getName()+"----"+s3.getAge()) ; s3.setName("赵又廷") ; s3.setAge(45) ; System.out.println(s1) ; System.out.println(s3); } }
Scanner:java.util的类:文本扫描器 一直在用这个:录入录入数据 构造方法 public Scanner(InputStream source) 成员方法: 判断功能 haxNextXXX():判断下一个录入都是是否是XXX类型 public boolean hasNextInt(): public boolean hasNextLine(). 获取功能 nextXXX() public int nextInt() public String nextLine() public String next() ... public class ScannerDemo { public static void main(String[] args) { //public Scanner(InputStream source):形式参数时候一个抽象类,需要有子类对象 //System类中存在一个"标准输入流"in //public static final InputStream in InputStream inputStream = System.in ; //字节输入流 //创建键盘录入对象 Scanner sc = new Scanner(inputStream) ; System.out.println("录入一个数据:"); /* int num = sc.nextInt(); //获取功能 System.out.println(num);*/ //java.util.InputMismatchException:录入的数据和需要接收的num类型不匹配 //Scanner类的提供的判断功能 if(sc.hasNextInt()){ //录入的int类型 //接收int int num = sc.nextInt() ; System.out.println("您输入的数据是:"+num); }else if(sc.hasNextLine()){ //录入的String String line = sc.nextLine() ; System.out.println("您输入的数据是:"+line); }else{ System.out.println("对不起,没有提供其他接收的类型值..."); } } }
11.1 键盘录入的细节: 录入的字符串和,int类型 先录入int,在录入字符串:字符串数据被漏掉 原因:"回车符号"的问题,如何解决: 1)可以使用next()---->录入的也是字符串 2)在录入String之前,在创建一个新键盘录入对象:比较麻烦:比较耗内存 应用场景: 后面集合就会用到:TreeSet集合(红黑树结构): 针对元素进行排序(自然排序/比较强排序) 键盘录入5个学生的语文成绩,英语成绩,数学成绩,姓名需要将5个学生的总分从高到底进行排序(TreeSet讲) Student int math; int english; int chinese; String name ; 有String,有int数据的录入----->统一使用String接收 "98","97","89" String--> Integer-->int public class ScannerDemo2 { public static void main(String[] args) { //创建键盘录入对象 Scanner sc = new Scanner(System.in) ; //提示并录入 System.out.println("请您输入第一个数据:"); int a = sc.nextInt() ; System.out.println("请您输入第二个数据:"); // Scanner sc2 = new Scanner(System.in) ; // String b = sc2.nextLine() ;//录入的一行内容 String b = sc.next() ; System.out.println("a:"+a+",b:"+b); } }
12.1 String的描述
String类代表字符串. Java程序中的所有字符串文字(例如"abc" )都被实现为此类的实例。"字符串本身就是常量" String的特点: 字符串不变的; 它们的值在创建后不能被更改 推荐方式: String 变量名 = "字符串常量" ; 知道:构造方法有哪些 public String():无参构造 String(byte[] bytes):将字节数组可以构造字符串对象 public String(byte[] bytes,int offset,int length)一部分字节数组构造成字符串对象 public String(char[] value):将字符数组构造成字符串对象 public String(char[] value, int offset,int count):将一部分字符数组构造成字符串对象 public String(String original):创建一个字符串对象,里面存储字符串常量 面试题: 数组中有没有length(),字符串String类中有没有length(),集合中有没有length()? 没有length(),只有length属性 String:有 集合:没有----获取长度:size() public int length():获取字符串长度 null :空值 :没有对象 引用数据类型的默认值 String s = null ; String s = "" ; 空字符序列,有,是空的,存在对象! // String s = new String("") ; //举例: public class StringDemo { public static void main(String[] args) { //构造方法测试 // public String():无参构造 String s1 = new String() ; System.out.println("s1:"+s1) ; System.out.println(s1.length()) ; System.out.println("---------------------------------------") ; //String(byte[] bytes):将字节数组可以构造字符串对象 //创建一个字节数组 byte[] bytes = { 97,98,99,100,101} ; String s2 = new String(bytes) ; //字符串底层有字符序列:字符数组----将97 寻找ASCII码表的字符内容 System.out.println("s2:"+s2); System.out.println(s2.length()); System.out.println("---------------------------------------") ; // public String(byte[] bytes,int offset,int length)一部分字节数组构造成字符串对象 //参数1:字节数组对象,参数2:起始索引 参数3:指定长度 String s3 = new String(bytes,1,3) ; System.out.println("s3:"+s3) ; System.out.println(s3.length()); System.out.println("---------------------------------------") ; //public String(char[] value):将字符数组构造成字符串对象 //创建一个字符串数组 char[] chs = {'h','e','l','l','o','高','圆','圆'} ; String s4 = new String(chs) ; System.out.println("s4:"+s4) ; System.out.println(s4.length()); System.out.println("---------------------------------------") ; //public String(char[] value, int offset,int count):将一部分字符数组构造成字符串对象 String s5 = new String(chs,5,3) ; System.out.println("s5:"+s5) ; System.out.println(s5.length()); System.out.println("---------------------------------------") ; //public String(String original):创建一个字符串对象,里面存储字符串常量 String s6 = new String("hello") ; System.out.println("s6:"+s6); System.out.println(s6.length()); /* String s7 = "hello" ; System.out.println("s7:"+s7); System.out.println(s7.length());*/ } }
12.2 字符串的特点
字符串的特点: 字符串不变的; 它们的值在创建后不能被更改 值:常量地址值... 字符串是常量:在内存中:方法区中的常量池中存储(池化技术...) 面试题: String s = "hello" ; 和 String s2 = new String("hello") ;两个有什么区别,分别创建了几个对象! 共同点:都是在创建一个字符串对象"hello" 但是内存执行不一样 前者:只是在常量池中开辟空间,创建一个对象 :推荐这种方式,节省内存空间! 后者:在堆中开辟空间,而且里面存在常量----常量池中标记 ,创建两个对象 //举例: public class StringDemo2 { public static void main(String[] args) { String s1 = "hello" ; //创建一个字符串对象 String s2 = new String("hello") ; System.out.println(s1 == s2) ; System.out.println(s1.equals(s2)) ; //String已经重写了Object的equals方法:默认比较就不是地址值而是内容是否相同 } }
12.3 String类的获取功能
String类的获取功能: char charAt(int index) :获取指定索引出的字符值 public String concat(String str):拼接功能:拼接新的字符串 public int indexOf(int ch):返回指定字符第一次出现的字符串内的索引 int lastIndexOf(int ch) :查询指定字符最后一次出现的索引值 int length() :获取字符串长度 public String[] split(String regex):字符串的拆分方法:返回的字符串数组 (重要) String substring(int beginIndex) :字符串截取功能 (重要) 默认从beginIndex起始索引截取到末尾 public String substring(int beginIndex,int endIndex) :从指定位置开始截取到指定位置结束(包前不包后) 包含beginIndex位置,不包含endIndex位置,包含到endIndex-1 //举例: public class StringDemo { public static void main(String[] args) { //测试 //创建一个字符串 String s = "helloworldJavaEE" ; // char charAt(int index) :获取指定索引出的字符值 System.out.println("charAt():"+s.charAt(4)) ; System.out.println("--------------------------------------") ; // public String concat(String str):拼接功能:拼接新的字符串 System.out.println("concat():"+s.concat("Android")) ;//拼接功能 System.out.println(s+"IOS");//拼接符号 System.out.println("---------------------------------------") ; // public int indexOf(int ch):返回指定字符第一次出现的字符串内的索引 //参数为字符/或int: int的值也可以找ASCII码表的字符 System.out.println("indexOf():"+s.indexOf('l')); //int lastIndexOf(int ch) :查询指定字符最后一次出现的索引值 System.out.println("lastIndexOf():"+s.lastIndexOf('l')); System.out.println("---------------------------------------") ; // public String[] split(String regex):字符串的拆分方法:返回的字符串数组 (经常用到) //参数可以是正则表达式或则普通字符串---分割符号 //创建一个新的字符串对象 String str = "Java-Php-Go-R-Python-C-C++-C#-Net" ; String[] strArray = str.split("-") ; for(int x = 0 ; x < strArray.length ; x++){ System.out.print(strArray[x]+" "); } System.out.println(); System.out.println("---------------------------------------") ; //截取: /** * String substring(int beginIndex) :字符串截取功能 (重要) * 默认从beginIndex起始索引截取到末尾 * public String substring(int beginIndex,int endIndex) :从指定位置开始截取到指定位置结束(包前不包后) * 包含beginIndex位置,不包含endIndex位置,包含到endIndex-1 */ System.out.println("subString():"+s.substring(5)); System.out.println("subString():"+s.substring(5,10)); } }
12.4 String类的转换功能
public char[] toCharArray():将字符串转换字符数组 byte[] getBytes() :使用平台的默认字符集进行编码过程:将字符串--->字节数组 byte[] getBytes(String charset):使用指定的字符集进行编码 "GBK/UTF-8" 编码和解码 编码:将能看懂的字符串---->看不懂的字节 解码:将看不懂的字节----->能看懂的字符串 public String toLowerCase():将字符串中的每一个字符转换成小写 public String toUpperCase():将字符串中的每一个字符转换成大写 static String valueOf(boolean b/float/long/double/int/char /....Object) 万能方法:将任意的数据类型转换成String :静态的功能 //举例: ublic class StringDemo2 { public static void main(String[] args) { //有一个字符串 String s = "helloworld" ; //public char[] toCharArray():将字符串转换字符数组 char[] chs = s.toCharArray(); for (int i = 0; i < chs.length; i++) { System.out.println(chs[i]); } System.out.println("---------------------------------------------") ; // byte[] getBytes() :使用平台的默认字符集进行编码过程:将字符串--->字节数组 byte[] bytes = s.getBytes() ; // System.out.println(bytes); //看到字节数组的内容: 使用数组工具Arrays //static String toString(任何类型的数组) :静态功能---将任何类型的数组转换成字符串形式 System.out.println(Arrays.toString(bytes)); //[104, 101, 108, 108, 111, 119, 111, 114, 108, 100] :英文:寻找它的ASCII码表 System.out.println("---------------------------------------------") ; //public String toLowerCase():将字符串中的每一个字符转换成小写 //public String toUpperCase():将字符串中的每一个字符转换成大写 System.out.println(s.toLowerCase()); System.out.println(s.toUpperCase()); System.out.println("---------------------------------------------") ; /** * static String valueOf(boolean b/float/long/double/int/char /....Object) * 万能方法: * 将任意的数据类型转换成String :静态的功能 */ int i = 100 ;//int String result = String.valueOf(i); System.out.println(result) ;//数字字符串 "100" } }
12.5 String的判断功能
String的判断功能 public boolean contains(String s):判断是否包含子字符串 public boolean startsWith(String prefix):判断是以指定的字符串开头 public boolean endsWith(String suffix):判断是是以指定的字符串结尾 boolean equals(Object anObject) :判断字符串内容是相等:区分大小写 boolean equalsIgnoreCase(String anotherString) :判断字符串内容是否相等,忽略大小写 public boolean isEmpty():判断字符串是否为空 public class StringDemo { public static void main(String[] args) { //String字符串 String s = "helloJavaee" ; // public boolean contains(String s):判断是否包含子字符串 System.out.println("contains():"+s.contains("hel")); System.out.println("contains():"+s.contains("ak47")); // public boolean startsWith(String prefix):判断是以指定的字符串开头 // public boolean endsWith(String suffix):判断是是以指定的字符串结尾 System.out.println("-----------------------------------------------") ; System.out.println(s.startsWith("hel")); System.out.println(s.startsWith("高圆圆")); System.out.println(s.endsWith("ee")); System.out.println(s.endsWith("wor")); System.out.println("-----------------------------------------------") ; String s2 = "helloJavaEE" ; System.out.println(s.equals(s2)) ; //区分大小写 //boolean equalsIgnoreCase(String anotherString) System.out.println(s.equalsIgnoreCase(s2));//不区分大小写 s = "" ; System.out.println(s.isEmpty()); } }
12.6 String类的其他功能
String类的其他功能 public String replace(char oldChar,char newChar):将新的字符值把旧的字符替换掉 public String replace(String oldChar,String newChar):将新的字符串值把旧的字符串替换掉 public String replaceAll(String regex,String replacement):使用指定的replacement替换的字符串内容 将符号正则表达式的匹配的字符串替换掉 (用到正则表达式使用) 参数1:正则表达式 举例: [0-9] public String trim():去除字符串前后两端空格 一般用在:IO中传输文件(读写文件) //举例: public class StringDemo { public static void main(String[] args) { //public String replace(char oldChar,char newChar):将新的字符值把旧的字符串替换掉,返回的新的自测 String s = "helloworld" ; System.out.println("replace():"+s.replace('l','k')) ; System.out.println("replace():"+s.replace("world","高圆圆")); System.out.println("--------------------------------------------------") ; //public String trim():去除字符串前后两端空格 (IO流中,上传文件:保证读取文件内容,先去除两端空格) String s2 = " javaEE " ; System.out.println("s2:"+"-----"+s2+"-----"); System.out.println("-------------------------------------") ; System.out.println("s2:"+"-----"+s2.trim()+"-----"); } }
面试题: 考源码 public int compareTo(String anotherString) :如何进行字典比较 String s1 = "hel" ; String s2 = "hello" ; 结果是多少,为什么这个值? public class StringDemo2 { public static void main(String[] args) { String s1 = "hel" ; String s2 = "abc" ; String s3 = "hello" ; //public int compareTo(String anotherString) :如何进行字典比较 //英文字符:字典顺序比较:abcdefgh.... System.out.println(s1.compareTo(s2)) ; System.out.println(s1.compareTo(s3)) ; } }
String,作为形式参数传递,有什么特点?
String类型作为形式参数和基本类型作为形式的效果一样,
形式参数的改变不会直接影响实际参数,String类型特殊的引用类型!
其他引用数据类型,形式参数的改变会直接影响实际参数!
StringBuffer: 简称"字符串缓冲",线程安全的,而且可变的字符序列! 线程: -----多线程:Thread 单线程 :程序的执行路径只有一条 ,不考虑安全性,只考虑效率! 多线程 :程序的执行路径有多条,考虑安全性,效率问题不是重点! 面试题:StringBuffer和StringBuilder有什么区别? 共同点:两者都是字符串区,支持可变的字符序列,而且都有互相兼容的API(功能相同的) 不同点: 前者:线程安全的类,多线程环境下使用居多-----同步(安全)----->执行效率低 银行的网站/医疗网站 后者:线程不安全的类,单线程程序中使用居多---->不同步(不安全)----->执行效率高\ 论坛的网站... StringBuffer的构造方法 StringBuffer();无参构造方法 :使用居多 StringBuffer(int capacity):指定容量大小的字符串缓冲区 StringBuffer(String str) :指定缓冲区的具体内容str,容量大小=16个默认容量+当前字符串长度 public int length()获取字符缓冲区中的长度 public int capacity():获取字符串缓冲区中的容量大小 public class StringBufferDemo{ public static void main(String[] args) { // StringBuffer();无参构造方法 //创建一个字符串缓冲区对象 StringBuffer sb = new StringBuffer() ; //默认的初始化容量16个(足够用了) System.out.println("sb:"+sb) ; System.out.println(sb.length()) ; System.out.println(sb.capacity()) ; System.out.println("-------------------------") ; // StringBuffer(int capacity):指定容量大小的字符串缓冲区 StringBuffer sb2 = new StringBuffer(50) ; System.out.println("sb2:"+sb2); System.out.println(sb2.length()); System.out.println(sb2.capacity()); System.out.println("-------------------------") ; // StringBuffer(String str) : String s = "helloworld" ; StringBuffer sb3 = new StringBuffer(s) ; System.out.println("sb3:"+sb3); System.out.println(sb3.length() ); System.out.println(sb3.capacity() ); //StringBuffer sb4 = "hello" ; //不能这样写 /* String str = "hello" ; StringBuffer sb4 = str ;*/ } }
13.1 StringBuffer:添加字符序列/删除
StringBuffer: 添加字符序列 StringBuffer append(任何数据类型):将任何数据类型的数据追加字符序列中(字符串缓冲区) StringBuffer insert(int offset, String str) :插入元素:在指定位置插入指定的元素 删除: public StringBuffer deleteCharAt(int index):在指定的位置处删除的指定的字符,返回字符串缓冲区本身 public StringBuffer delete(int start,int end):删除指定的字符从指定位置开始,到end-1处结束 //举例: public class StringBufferDemo2 { public static void main(String[] args) { //创建一个字符串缓冲区对象 StringBuffer sb = new StringBuffer() ; System.out.println("sb:"+sb); // StringBuffer append(任何数据类型):将任何数据类型的数据追加字符序列中(字符串缓冲区) /* StringBuffer sb2 = sb.append("hello"); StringBuffer sb3 = sb2.append('A'); StringBuffer sb4 = sb3.append(12.56); StringBuffer result = sb4.append(100); System.out.println(result);*/ sb.append("hello"); sb.append("world") ; sb.append("javaee") ; /* sb.append('A'); sb.append(true) ; sb.append(13.45) ; sb.append(100) ; sb.append(new Object()) ; System.out.println("sb:"+sb);*/ System.out.println("sb:"+sb) ; // StringBuffer insert(int offset, String str) sb.insert(5,"高圆圆") ; System.out.println("sb:"+sb); //hello高圆圆worldjavaee System.out.println("----------------------------------------------------------") ; // public StringBuffer deleteCharAt(int index) //需求:删除第一个e字符 System.out.println(sb.deleteCharAt(1)); //需求:删除第一个l字符 System.out.println(sb.deleteCharAt(1)); //public StringBuffer delete(int start,int end) System.out.println(sb.delete(3,7)); } }
13.2 StringBuffer反转功能
public StringBuffer reverse():反转功能 //举例: public class StringBufferDemo3 { public static void main(String[] args) { //已知一个字符串: /* String s = "helloworld" ; //s---->StringBuffer类型 StringBuffer sb = new StringBuffer(s) ; //利用功能 StringBuffer sb2 = sb.reverse(); String result = sb2.toString(); System.out.println(result);*/ //键盘录入一个字符串:将字符串反转 Scanner sc = new Scanner(System.in) ; //提示并录入数据 System.out.println("请您输入一个字符串:") ; String line = sc.nextLine() ; //调用功能改进---->String String result = reverse(line); System.out.println(result); } public static String reverse(String s){ //s---->StringBuffer //分步实现 // StringBuffer sb = new StringBuffer(s) ; // //反转---并且转换String // String result = sb.reverse().toString(); // return result ; //一步走 return new StringBuffer(s).reverse().toString() ; } }
String substring(int start):从指定位置截取到默认结束,返回的新的字符串 String substring(int start, int end) :从指定位置开始截取,到指定位置结束(包前不包后) //举例: public class StringDemo4 { public static void main(String[] args) { StringBuffer sb = new StringBuffer() ; sb.append("helllo") ; sb.append("world") ; System.out.println(sb) ; //截取 String resultStr = sb.substring(5); System.out.println(resultStr) ; //返回的被截取的字符串内容 System.out.println("-------------------------------------") ; String resultStr2 = sb.substring(5, 9); System.out.println(resultStr2); } }
13.3 StringBuffer <-----> String 互相转换
开发中:引用类型 有可能将A类型转换成B类型,结果最终需要的是B类型 有的时候,A类型---->B类型----->A类型 可能需要用B类型的功能,但是结果需要的是A类型,又需要转回去 StringBuffer <-----> String //举例: public class StringBufferTest { public static void main(String[] args) { //String------->StringBuffer //方式1:使用StringBuffer的有参构造方法 //StringBuffer(String s) String s = "helloJavaEE" ; StringBuffer sb = new StringBuffer(s) ; System.out.println("sb:"+sb) ;//内容一样,但是数据类型不同 System.out.println("------------------------------") ; //方式2:使用StringBuffer无参构造方法+append(String s) StringBuffer sb2 = new StringBuffer() ; sb2.append(s) ; System.out.println("sb2:"+sb2) ; System.out.println("------------------------------------------") ; //StringBuffer-------->String //有一个StringBuffer的数据 StringBuffer buffer = new StringBuffer("android") ; //String类型构造方法:public String(StringBuffer buffer) String str = new String(buffer) ; System.out.println("str:"+str) ; System.out.println("------------------------------------------") ; //public String toString() String str2 = buffer.toString(); System.out.println("str2:"+str2); } }
13.4 String和StringBuffer有什么区别?
前者: String是常量,一旦被赋值,其值不能被更改;它的不可变的字符序列 开发中:前端提交后台的数据--------> String (它的功能远远大于StringBuffer) 作为形式参数,形式参数的改变不会影响实际参数,特殊的引用类型,和基本数据类型作为形式参数的效果一样 后者: StringBuffer是可变的字符序列,线程安全的类,同步,执行效率低,单线程程序中的使用StringBuilder替代StringBuffer 字符串缓冲区 里面存储的字符序列-------> 还需要转换成String类型 作为形式参数,形式参数的改变会直接影响实际参数!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。