1. 多态(重点)
1.1 什么是多态
现实世界事物描述:一个事物体现出的的不同形态! (主要体现在内存中)
例: 水这个事物,有: 液态,固态,气态
1.2 多态的前提条件
1)必须存在继承关系, 如果没有继承,谈不了多态! (继承的好处第三点)
2)必须存在方法重写,需要让子类完成自己的业务功能,需要将父类的某些功能进行覆盖(重写)
举例:动物都需要吃
只有见到具体动物---才知道吃什么,具体的动物的子类将"吃"的功能进行重写
3)需要存在"父类引用指向子类对象"
格式: Fu fu =new Zi() ;
父类名 对象名 = new 子类名() ; "向上转型"(使用的是父类的东西)
1.3 多态中的成员访问特点
1.3.1 格式
父类名 对象名 = new 子类名();
即Fu fu = new Zi();(向上转型,使用的是父类的东西)
1.3.2 访问成员
1) 成员变量:
编译看左,运行看左! (如果编译通过了,说明Fu中存在变量,运行看左,使用父类的东西)
2) 成员方法(非静态):
编译看左,运行看右.使用子类重写后的方法(因为子类出现了父类一模一样的方法声明,覆盖了)
3) 静态的成员方法:
算不上方法重写.和类相关的.称为"类成员"
编译看左,运行看左!
随着类的加载而加载,访问通过类名访问(推荐)
4) 构造方法:
因为存在继承关系,存在无参构造/有参构造,都需要父类先初始化,然后才是子类,分层初始化.
例:
//父类
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.4 多态的好处
1)可以提高代码的复用性(继承保证的)
2)可以提高代码的扩展性(由多态的保证:Fu fu = new Zi() 父类引用指向子类对象)
1.5 多态的弊端
多态的弊端:
格式:Fu fu = new Zi() :向上转型 (使用的是父类的东西)
不能访问子类的特有功能
现在就需要访问子类的特有功能:如何解决:
1)直接创建具体的子类: 子类new 子类
从内存角度考虑: 需要在堆内存中继续开辟空间,消耗内存空间
2)优化内存:
父类引用指向子类对象, 向下转型
格式:
Zi zi = (Zi)fu; 引用类型了
1.5.1 向下转型使用不当,出现异常
多态的在使用过程中,存在向上转型和向下转型,
向下转型使用不当,会出现问题:
java.lang.ClassCastException:类转换异常:
属于 "运行时期异常"----->代码不严谨导致的
例 : 由 "狗是动物"向下转为"狗是狗",
但是不可以再向下转型为 "猫是狗"
2. 抽象
2.1 抽象的定义
在现实事物中,将比较概括性的事物统称为"抽象的事物".
例:
猫和狗是具体的动物了,他们都继承自动物类,将动物就可以看成是一个抽象的事物;
猫和狗具体的功能应该具体体现,在动物事物中,应该给出一个声明即可,不需要具体体现!
2.2 抽象类的格式
abstract class 类名{}
2.3 抽象类的注意事项
1)在一个类中,如果当前类中存在抽象功能(方法),那么这个类必须抽象类;
2)一个抽象类中,不一定都都是抽象方法;
抽象方法:没有方法体的一个成员方法,并且携带一个关键字 abstract
权限修饰符 abstract 返回值类型 方法名(形式参数列表) ;
3)抽象类的子类:
为抽象类: 定会存在具体的子类,否则没有意义!
为具体类:它才有意义,可以创建实例!继承的抽象方法,必须重写.
4)抽象类的本质:
强制子类必须完成的事情!
2.4 抽象类的特点
不能实例化 (不能创建对象),即不能new对象,必须通过具体子类向上转型实现.
2.4.1 重写类的成员特点
成员变量:
既可以是变量,也可以是常量!
成员方法:
既可以是抽象方法,也可以是非抽象方法
构造方法:
存在无参/有参:分层初始化
目的:对数据进行初始化!
2.5 abstract 关键字和那些关键字冲突
private:
被private修饰的方法只能在本类访问, 有一个abstract关键字:强制子类重写.
final:
被final修饰的成员方法,不能被重写,而abstract强制子类重写
static:
被static修饰符的方法,需要被类名访问,随着类的加载而加载,而abstract需要让子类重写这个方法,通过对象名来访问(访问时机冲突)
方法重写的注意事项
子类继承父类: 重写父类的方法的时候,访问权限不能更低,跟父类的权限保持一致,否则报错!
2.6 抽象类面试题
例 : 一个类如果没有抽象方法,那么将这个类定义为抽象类有什么意义呢?
意义:
就是为了不让外界new对象:不能实例化 抽象类特点:不能实例化 (如何实例化,通过抽象类多态实例化:具体的子类)
这个类没有抽象方法,将它定义为抽象类:
举例:
后面的日历类Calendar(特殊的常用类之抽象类) 还有很多jdk提供的
里面会存在一些静态功能:返回值是它自己本身
public static Calendar getInstance()
3. 接口(重点)
3.1 什么是接口
接口实际就是描述事物本身之外的"额外功能(扩展功能)"
开发核心宗旨:面向接口编程
举例:
狗会站着走路, 这就是被训练出来的它本身不具备的额外功能.
3.2 接口格式
关键字interface 接口名{} ---- 接口的命名规则和类一样,"大驼峰命名法"
3.3 接口的特点
1)不能实例化
2)接口中成员方法:只能是抽象方法,不能有方法体;
3.4 接口如何实现
接口是比抽象类还抽象的一种概念!
接口的子类------>子实现类 (接口和实现类: 实现关系 : implements)
3.5 接口的注意事项
1)接口的子类可能是抽象类,那么肯定会存在最具体的子类,否则 没有意义!
2)具体类:就通过接口多态进行实例化!
接口名的 对象名 = new 子实现类名()
开发中:"接口和子实现类的定义名称的规则"
定义接口名之后:在定义子实现类的时候:名称都会在接口名的后面+Impl
3.6 接口中的成员特点
成员变量:
只能是常量:存在默认修饰符public static final 可以省略不写;
成员方法:
只能是抽象方法:存在默认修饰符 public abstract 可以省略不写;
构造方法:
接口没有构造方法,因为接口只是为了提供事物的额外功能,谁实现了接口,就具备这个功能!
3.7 面试题: 抽象类和接口的区别
1)成员区别
接口:
成员变量:只能是常量,存在默认修饰符 public static final 可以省略
成员方法:只能是抽象方法,存在默认修饰符 public abstract 可以省略
构造方法:接口没有
抽象类:
成员变量:即可以是常量,也可以是变量
成员方法:既可以存在抽象方法,而且抽象方法abstract不能省略,也可以存在非抽象方法\
构造方法:存在:无参/有参,继承关系, 先让父类初始化,然后在是子类初始化(分层初始化)
2)关系的区别
类与类之间关系:
继承关系 extends 只支持单继承,不支持多继承,但可以多层继承
类与接口之间的关系:
实现关系 implements一个类继承另一个类的同时,可以实现多个接口
接口与接口之间关系:
继承关系 extends 不仅支持单继承,也可以多继承,也可以多层继承!
3)设计理念的区别
抽象类:
存在继承关系extends, 继承体现的是"is a"的关系
接口:
存在实现关系implements,仅仅是将额外功能提供相关的事物,这个事物要具备额外功能必须实现这个接口, 体现的是一种"like a"的关系
3.8 面试题: 什么时候使用继承
不能为了使用部分功能,而是使用继承,因为B类继承自A类,可以将所有方法继承过来,但是A类中有的成员方法B类可能不需要,
继承的本身弊端:
具有局限性!
什么时候用继承的概念?
如果B类是A类的一种,或者A类是B类一种,这个时候就可以使用继承
继承的体系的是一种"is a"的关系!
4. 形式参数问题研究
4.1 方法的形参是基本数据类型
实际参数需要传递当前具体的基本类型的数据值即可
4.2 方法 方法的形式参数是引用数据类型:
4.2.1 具体类:
调用该方法,实际参数需要传递的是当前具体类对象
例:
class Student{
public void study(){
System.out.println("学习JavaSE...");
}
}
class StudentDemo{
//成员方法
public void method(Student student){ //形式参数是引用类型:Student:具体类---->实际参数需要创建Student类的具体对象
student.study() ;
}
}
//测试类
public class ArgsDemo1 {
public static void main(String[] args) {
//需要调用StudentDemo类中的method方法
//创建StudentDemo类的对象
StudentDemo sd = new StudentDemo() ;
sd.method(new Student());//匿名对象
System.out.println("---------------------------") ;
//方式2:创建一个学生对象
Student s = new Student() ;
sd.method(s) ;
}
}
4.2.2 抽象类:
抽象类:
调用该方法,实际参数需要传递的是当前抽象类的子类对象,抽象类多态完成!
示例:
abstract class Person{
//定义一个非抽象方法
/*public void work(){
System.out.println("人都需要工作...");
}*/
public abstract void work() ;
}
//定义一个类
class PersonDemo{
//成员方法
public void show(Person person){
//方法的形式参数是引用类型:抽象类--->调用该方法实际参数需要传递当前抽象类的子类对象:抽象类多态
person.work() ;
}
}
//抽象类不能new,需要将具体的子类定义出来
//程序员
class Programmer extends Person{
@Override
public void work() {
System.out.println("程序员日日夜夜敲代码...");
}
}
//经理
class Manager extends Person{
@Override
public void work() {
System.out.println("不断的谈需求,解决技术难点...");
}
}
//测试类
public class ArgsDemo2 {
public static void main(String[] args) {
//需求:调用PersonDemo类中的show方法
PersonDemo pd = new PersonDemo() ;
//Person p = new Person() ; //抽象类不能实例化
//抽象类多态
Person p = new Programmer() ;//向上转型
pd.show(p) ;
Person p2 = new Manager() ;
pd.show(p2) ;
System.out.println("-------------------------------------") ;
//匿名对象
pd.show(new Manager()) ;
pd.show(new Programmer()) ;
}
}
4.2.3 接口
接口:
调用该方法,实际参数需要传递的是当前接口的子实现类对象:接口多态
示例:
//定义一个接口
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());
}
}
5. 权限修饰符的范围
修饰符 范围
在同一个包下 在同一个包下 在不同包下的子类中 在不同包下的无关类中
的当前类 的子类中/无关类
private Y
默认修饰符 Y Y
protected: Y Y Y
受保护的
public Y Y Y Y
四个权限修饰符的优先级: 从大到小
public > protected > 默认修饰符 > private
6. 返回值问题的研究
6.1 方法的返回值类型: 基本数据类型:
最终通过功能的业务操作,返回的数据结果
6.2 引用数据类型(重点)
6.2.1 具体类:
如果一个方法的返回值是一个具体类,那么该方法就需要返回当前类具体对象!
示例:
class Student{
public void study(){
System.out.println("学习JavaEE...");
}
}
class StudentDemo{
//定义一个成员方法
public Student method(){//返回值类型时一个引用类型:具体类, 调用该方法的时候,需要返回的当前具体类对象!
//方式1:有名字对象
Student s = new Student() ;
return s ;
//方式2:匿名对象
return new Student() ;
}
}
//测试类
public class ReturnDemo1 {
public static void main(String[] args) {
//需求:调用StudentDemo类的method方法
StudentDemo sd = new StudentDemo() ;
Student student = sd.method();//这个方法完成事情 Student student = new Student() ;
student.study() ;
}
}
6.2.2 抽象类:
如果一个方法的返回值是一个抽象类型,那么该方法需要返回当前抽象类的子类对象,抽象类多态!
示例:
abstract class Person{
//抽象方法
public abstract void work();
}
class PersonDemo{
public Person show(){
//??
// Person person = new Person() ;//抽象类不能new ,不能实例化,只能 通过抽象类多态,子类进行实例化
//方式1:抽象类多态
Person p = new Worker() ;
return p ;
//方式2:匿名对象
return new Worker() ;
}
}
//定义Person类的子类
class Worker extends Person{
@Override
public void work() {
System.out.println("爱生活,爱Java...");
}
}
//测试类
public class ReturnDemo2 {
public static void main(String[] args) {
//需求:调用PersonDemo类中的show方法()
PersonDemo pd = new PersonDemo() ;
Person person = pd.show(); //实际业务: Person person = new Worker() ;
person.work() ;
}
}
6.2.3 接口:
如果一个方法的返回值是接口类型,那么该方法需要返回的是当前接口的子实现类对象,接口多态!
示例:
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();
}
}
7. 包在开发中的真实意义
包:package ---目录(文件夹)的意思
开发中:都使用的多级包中间.隔开
真实开发场景中:包的命名规则
多级包:都是公司域名反写
istone.net.dev.xx
通过包名--------------------------->区分代码的层次结构的!
istone.net.dev.pojo/公司域名反写.entity/公司域名.domain:
实体类所在的包:提供这些类的属性私有化,构造方法 setXXX()/geXXX()
User类
Product类
Student类
描述现实世界的事物------"数据库中数据表"
公司域名反写.dao: 包下存储的代码--->数据库的操作代码(JDBC:Java连接数据库)
dao:数据访问对象data access Object
8. 内部类
8.1 什么是内部类:
在一个类A中定义另一个类B,那么将类B就称为类A的内部类;类A是它的外部类!
8.2 内部类分类
内部类:
成员内部类:在一个类的成员位置定义的
局部内部类:在一个类的成员方法中定义的
8.3 成员内部类
8.3.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() ;
}
}
8.3.2 成员内部类中的修饰符
静态的成员内部类中的成员方法(静态的还是非静态),访问外部类的成员变量,都必须是静态的
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() ; //静态的成员内部类的静态成员方法(推荐这种访问)
}
}
8.4 匿名内部类
没有名字的类
8.4.1 格式:
new 类名/接口名(){ 一般类名--->抽象类
重写抽象方法(){
业务功能;
}
} ;
8.4.2 匿名内部类的本质:
就是继承了该抽象类或者实现了该接口子类对象;
8.4.3 应用场景:
匿名内部类的使用在方法定义中或者是方法声明上:局部位置中使用
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 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() ;
}
}
8.5 局部内部类
8.5.1 特点
局部内部类可以访问外部类的成员吗?
可以,包括私有;
8.5.2 面试题
面试题:
局部内部类访问局部变量的时候,有什么要求?为什么?
要求当前的局部变量为常量:加入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. Object 类
Object是类Object结构的根。 每个类都有Object作为超类(父类)
9.1 常用功能
大部分常用类已经将这些功能重写了
public final Class getClass():表示正在运行的类的实例! (当前类的字节码文件对象)(重点)
public int hashCode():哈希码值,把它可以看成是一个"地址值",不是真实意义的地址值,和哈希表有关!(了解)
不同的对象,哈希码值不同
Class---->后期反射中讲
成员方法:
public String getName():获取当前正在运行的的类名,表现字符串形式
9.2 常用类
JavaSE---->JavaEE:做项目中会使用大量的写Java中常使用的接口或者类
举例:
集合 String Date日期 StringBuffer 线程Thread IO流程:InputStram/OutputStream:数据传输 网络编程 反射
10. 面试题:获取一个类的字节码文件对象的方式有几种?
1)Object的方法 public final Class getClass()
2)任意Java类型的class属性
3)
11. 带包的编译额运行
11.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_同一个包下的编译和运行>
11.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
12. Object类中的方法
12.1 public String toString()
返回对象的字符串表示形式
如果方法没有被重写:
New对象,输出对象名打印的会是地址值,没有实际意义.
所以建议所有子类覆盖此方法:
输出对象名称,看到的是当前这个对象的成员信息表达式!
12.2 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方法
12.3 protected Object clone(): 浅克隆
throws CloneNotSupportedException:调用过程中可能存在克隆不支持的异常
对于jdk提供的类的方法本身存在异常.谁调用这个方法,必须做出处理,否则报错,最简单的方式继续往上抛 throws
创建并返回此对象的副本(浅克隆) :了解
简单理解:复制对象,获取对象的成员...
13. Scanner类
java.util的类:文本扫描器,不属于lang包下,使用必须导包
构造方法
public Scanner(InputStream source)
成员方法:
判断功能 haxNextXXX():判断下一个录入都是是否是XXX类型
public boolean hasNextInt():
public boolean hasNextLine().
获取功能 nextXXX()
public int nextInt()
public String nextLine()
public String next()
...
13.1 键盘录入的细节:
录入的字符串和,int类型
先录入int,在录入字符串:字符串数据被漏掉
原因:
"回车符号"的问题,如何解决:
1)可以使用next()---->录入的也是字符串
2)在录入String之前,在创建一个新键盘录入对象:比较麻烦:比较耗内存
14. String类(重点)
14.1 String的描述
String类代表字符串。
'Java程序中的所有字符串文字(例如"abc" )都被实现为此类的实例。 "字符串本身就是常量"
14.2 String的特点:
字符串不变的; 它们的值在创建后不能被更改
推荐方式:
String 变量名 = "字符串常量" ;
14.3 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):创建一个字符串对象,里面存储字符串常量
14.4 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():判断字符串是否为空
14.5 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 :静态的功能
14.5 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
14.6 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中传输文件(读写文件)
14.7 字符串的特点:
字符串不变的;
它们的值在创建后不能被更改
值:常量地址值...
字符串是常量:
在内存中:方法区中的常量池中存储(池化技术...)
14.8 面试题
String s = "hello" ;
和
String s2 = new String("hello") ;两个有什么区别,分别创建了几个对象!
共同点:
都是在创建一个字符串对象"hello"
但是内存执行不一样
前者:只是在常量池中开辟空间,创建一个对象 :推荐这种方式,节省内存空间!
后者:在堆中开辟空间,而且里面存在常量----常量池中标记 ,创建两个对象
14.9 面试题: 数组中有没有length(),字符串String类中有没有length(),集合中有没有length()?
数组:
没有length(),只有length属性
String:
有长度方法. str.length()
集合:
没有----获取长度:size()
public int length():获取字符串长度
null :空值 :没有对象 引用数据类型的默认值
String s = null ;
String s = "" ; 空字符序列,有,是空的,存在对象!// String s = new String("") ;
14.10 面试题: 考源码
ublic 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)) ;
}
}
/**
字典顺序比较:
1)如果从第一个字符开始,就不同,结果就是.前的对象第一个字符对应的ASCII码表得值减去后一个字符的值.
2)第一个相同: 开始比较往后比较,如果有不同的,再用ASCII码表值相减.
3)短的字符串属于长的字符串子串,则值是.前的对象长度减去点后的对象长度.
*/
14.11 String,作为形式参数传递,有什么特点?
String类型作为形式参数和基本类型作为形式的效果一样,
形式参数的改变不会直接影响实际参数,String类型特殊的引用类型!
其他引用数据类型,形式参数的改变会直接影响实际参数!
15. Integer类
15.1 拆装箱
jdk7以后:自动拆装箱特性
基本数据类型---->默认提示为 引用数据类型 "装箱"
引用数据类型------>基本数据类型 "拆箱"
15.2 类型转换
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
Integer:Integer类包装一个对象中的原始类型int的值
//public static String toBinaryString(int i):将整数转换字符串形式的二进制
public static String toOctalString(int i) :将整数转换字符串形式的八进制
public static String toHexString(int i):将整数转换成字符串形式的十六进制
示例:
public class IntegerDemo {
public static void main(String[] args) {
//求出一个数据的十进制---->二进制 八进制 十六进制
System.out.println(Integer.toBinaryString(100)) ;
System.out.println(Integer.toOctalString(100)) ;
System.out.println(Integer.toHexString(100)) ;
//求出int类型的取值范围
//静态的常量值
//public static final int MAX_VALUE
//public static final int MIN_VALUE
System.out.println(Integer.MIN_VALUE) ;
System.out.println(Integer.MAX_VALUE) ;
}
}
15.3 Integer的构造方法
Integer(int value):将int类型构造成Integer对象
Integer(String s) throws NumberFormatException :将String类型构造成Integer对象
前提条件:要使用第二个构造方法,前提是必须是数字字符串
示例:
public class IntegerDemo2 {
public static void main(String[] args) {
//有一个int类型
int i = 100 ;
// Integer(int value):将int类型构造成Integer对象
Integer ii = new Integer(i) ;
System.out.println(ii); //100
System.out.println("-------------------------") ;
//String s = "hello100" ;
String s = "200" ;
//Integer(String s) throws NumberFormatException
Integer i2 = new Integer(s) ;
System.out.println("i2:"+i2) ;//200
}
}
15.4 看程序,写结果
Integer 变量名 = 整数;
执行底层:Integer的静态功能valueOf(int i)
public static Integer valueOf(int i) {
//静态的成员内部类:内部缓存区:IntegerCache
if (i >= IntegerCache.low && i <= IntegerCache.high){
//看当前传进来的整数值是否在-128-127之间
return IntegerCache.cache[i + (-IntegerCache.low)]; //从内部缓存区中取出数据
}
return new Integer(i); //如果没有在范围内:就会创建新的Integer对象
}
示例:
Integer i9 = 128 ; // 记住取值范围: -128-127
Integer i10 = 128 ;
System.out.println(i9==i10) ; //false
System.out.println(i9.equals(i10));//true
16. StringBuffer类
简称"字符串缓冲",线程安全的,而且可变的字符序列!
16.1 线程(Thread)
单线程 :程序的执行路径只有一条 ,不考虑安全性,只考虑效率!
多线程 :程序的执行路径有多条,考虑安全性,效率问题不是重点!
16.2 面试题
StringBuffer和StringBuilder有什么区别?
共同点:
两者都是字符串区,支持可变的字符序列,而且都有互相兼容的API(功能相同的)
不同点:
前者:线程安全的类,多线程环境下使用居多-----同步(安全)----->执行效率低
行的网站/医疗网站(不是谁都能随便搞事)
后者:线程不安全的类,单线程程序中使用居多---->不同步(不安全)----->执行效率高\
论坛的网站...(有水军能匿名搞事)
16.3 StringBuffer的构造方法
StringBuffer();无参构造方法 :使用居多
StringBuffer(int capacity):指定容量大小的字符串缓冲区
tringBuffer(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 ;*/
}
}
16.4 添加/删除
添加字符序列:
StringBuffer append(任何数据类型):将任何数据类型的数据追加字符序列中(字符串缓冲区)
StringBuffer insert(int offset, String str) :插入元素:在指定位置插入指定的元素
删除字符序列:
public StringBuffer deleteCharAt(int index):在指定的位置处删除的指定的字符,返回字符串缓冲区本身
public StringBuffer delete(int start,int end):删除指定的字符从指定位置开始,到end-1处结束
16.5 反转功能
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() ;
}
}
16.5 开发中利用类型转换
开发中:引用类型
有可能将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);
}
}
16.6 String的截取类型
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);
}
}
17. 面试题: String和StringBuffer有什么区别?
前者:
String是常量,一旦被赋值,其值不能被更改;它的不可变的字符序列
开发中:前端提交后台的数据--------> String (它的功能远远大于StringBuffer)
作为形式参数,形式参数的改变不会影响实际参数,特殊的引用类型,和基本数据类型作为形式参数的效果一样
后者:
StringBuffer是可变的字符序列,线程安全的类,同步,执行效率低,单线程程序中的使用StringBuilder替代 StringBuffer
字符串缓冲区 里面存储的字符序列-------> 还需要转换成String类型
作为形式参数,形式参数的改变会直接影响实际参数