复习
Java基础语法
- 基本数据类型
- 4类8种
- 二进制、八进制、十六进制
- 运算符
- 算数
- 关系
- 逻辑
- 位运算符
- & | ! ^
- << >> >>>
- 三目运算符
- 控制语句
- 分支语句
- if if-else if -else if - else
- switch case
- 循环语句
- for
- while
- do-while
- 分支语句
- 方法
- 数组
面向对象编程
- 类和对象
- 类:对现实世界同一类事物的共同的特征的抽象
- 对象:类的实例,与现实世界一个具体的事物相对应
- 面向对象编程:是一种程序设计思想,使用类和对象进行程序设计
- 封装
- 使用private修饰类的属性,防止用户直接访问这些属性
- 使用public的get/set方法,让用户可以间接访问这些属性
- 继承
- 通过父类创建子类,子类继承(extends)父类,父类也成为超类或基类
- 子类继承父类除构造器以外的所有成员
- 为什么要继承/继承的好处?
- 实现代码的复用,减少重复的代码
- 继承是多态的基础
- 子类不能直接访问继承来的父类的私有成员,可以通过继承来的public的方法去访问
- 子类不能继承父类的构造器,可以通过
super()
和super(...)
调用父类的无参构造器或带参构造器 - 一个类的构造器的第一行, 一定是
this(...)
或super(...)
- 当创建一个子类对象时,父类的构造器一定会被调用
- 多态
- 代码角度:声明父类类型的引用,指向子类类型的实例
- 面向对象角度:一个对象的多种形态
- 本态:对象的本类形态
- 多态:对象的父类形态
- 多态的应用:
- 多态数组:声明父类类型的数组,其中既可以保存父类类型的对象,也可以保存子类类型的对象
- 多态参数:方法的参数列表中声明父类类型的参数,调用该方法时,既可以传入父类类型的对象,也可以传入子类类型的对象
- 多态的限制:
- 通过父类引用指向子类实现时,仅能够访问父类所有的成员,不能够访问子类特有的成员
- 可以通过强制类型转换,将父类引用转变成子类类型
- 格式: Son son=(Son)father;
- 避免类型转换异常: father instanceof Son
- 抽象类
- 代码理解:
- 使用abstract修饰的类
- 包含抽象方法的类
- 面向对象理解:
- 对现实世界同一大类下的不同事物的共同特征的抽象
- 举例:动物和鸟,宠物和猫
- 抽象类的成员:
- 在普通类的基础上多了抽象方法
- 抽象方法:
- 使用abstract修饰的方法
- 没有方法体
- 抽象类不能被实例化
- 具体子类继承抽象类,必须实现抽象类中定义的所有的抽象方法
- 具体子类适用抽象父类的多态
- 代码理解:
- 接口(interface)
- 代码理解:public interface 接口名()
- 面向对象理解:现实世界中不同类事物的共同的行为特征的抽象
- 接口的成员:
- 属性:都是静态常量
- 抽象方法:接口中声明的方法默认都是抽象方法
- 具体方法:在JDK8以后,接口中可以声明具体方法,必须使用default或static修饰
- 接口不能实例化
- 可以使用类(具体类或抽象类)来实现(implements)接口,一个类可以实现多个接口
- 如果一个具体类实现接口,必须实现接口中定义的所有抽象方法
- 接口的实现类适用于父接口的多态
- 接口可以被继承,但是只能被接口继承
- 面向接口编程:
- 可以通过接口来设计程序中的各类行为及规范
- 开发者可以基于接口定义的规范进行编程
常用的修饰符
- 访问控制修饰符
- private:本类中
- default:本类+同包
- protected:本类+同包+子类中
- public:所有位置
- static修饰符
- 将类的成员变成静态成员
- 静态成员保存在堆中的静态区中,与类绑定,也称为类成员,在类加载时初始化
- 可以通过类名.成语名直接访问
- 修饰属性
- 修饰方法
- 修饰代码块 -> 静态代码块 -> 初始化本类的静态成员
- 修饰内部类 -> 静态内部类
- static的应用:
- 静态常量
- 静态方法:工具方法
- final修饰符
- 修饰类:终类,不能被继承
- 修饰方法:最终方法,不能被重写
- 修饰属性:常量,赋值后不能被修改
- 空final变量:
- 在属性声明时,不给初始值
- 必须在构造方法中进行赋值
API(application programming interface)
API:别人写好的类和方法,供你直接调用
API文档:介绍都有哪些类和方法,方法的具体功能时什么,需要传入什么样的参数,返回值的格式是什么样的
所有的开发者,都必须掌握阅读API文档的能力
包(package)
- Java语言支持使用分层次的目录结构来管理类文件
- Java语言使用包的概念,包名与目录结构相对应
- 例如:
- 包名test,对应目录为test/
- 包名com.oracle,对应目录为com/oracle/
- 包括com.oracle.service,对应目录为com/oracle/service/
1. 用法
-
package,声明包,声明当前类所在的位置,在首行且只能出现一次
-
import,导入包,把不在当前包位置的类导入进来,不在首行且可以出现多次
-
Java中允许不同的包下出现同名的类,但是不允许在同一个包下出现同名的类
-
Java中允许在同一个类中使用来自不同包的同名的类
-
import语句可以指定默认使用的同名类是哪个
-
其他的同名类必须显式在类添加添加完整的包名,与默认的同名类相区别
-
Scanner s1=new Scanner(System.in);// import指定的 java.util.Scanner
jdk.nashorn.internal.parser.Scanner s2=new jdk.nashorn.internal.parser.Scanner();
package cn.tedu.packagex;
//*代表通配符,只能匹配到当前包下所有的类/接口
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class PackageDemo{
public static void main(String[] args){
newScanner(System.in);
/*Arrays.sort();
newConcurrentHashMap<>()*/
}
}
2. 提供包
-
API(Application Programming Interfaces)—应用程序接口(提供一系列的接口以及接口下的类)
API中提供的所有的方法要么是被protected修饰要么是被默认(public)来修饰
-
java(提供源生包)
- lang包—当程序启动时会自动加载lang包下(核心类库)的内容,使用时不需要导包
- util包(工具包)—提供大量可以操作对象和类的信息
- io包—数据传输
- math包—提供的是简单的数学运算
- net包—网络编程
- nio包—高并发
- sql包–操作数据库
- time包—提供时间和日期
-
javax(提供扩展包)
-
org(第三方厂商 Apache)
Object
1. 概念
- Object类是所有类的父类(根类),每个类默认继承Object类
- Java中所有的对象都适用于Object的多态
- Object o1=new xxx();
- public void method(Object o)
2. 重要方法
-
clone():新建对象,把原对象的属性值复制到新对象中并返回新对象的引用
-
Object中的clone()方法是protected修饰的,默认不支持在子类的外部直接访问
-
因此,需要子类重写clone()方法,将访问控制修饰符改为public,才能支持从外部直接访问
-
类实现Cloneable接口产生对象才能支持克隆操作
-
Object中的clone方法是native修饰的,表示底层基于其他语言实现具体逻辑,效率一般优于Java代码的实现,其执行的逻辑是在堆上创建一个新的对象,保证新对象的属性值和原对象的属性值是一致的,该方法返回的是新的对象的引用
-
因此,子类重写从父类继承来的clone方法时,仅需要修改访问控制修饰符,在代码中还是通过
super.clone()
求调用Object中的clone
方法 -
同时,子类重写方法需要修改返回值类型,改为当前类的类型,表示克隆后,返回的是当前类的对象
-
Java默认情况下,不允许一个类被克隆,以起到保护的作用,如果开发者认为一个类需要被克隆,应该主动让该类实现
java.lang.Cloneable
- Cloneable中并没有定义任何的抽象方法,仅作为一个标识存在
- 当开发者调用一个对象的clone方法时,编译器会检测该类是否实现了该接口,如果实现,则执行克隆方法,如果未实现,则抛出
java.lang.CloneNotSupportedException
异常
-
问题:一个类如果想要被克隆,需要哪些操作?
- 实现Cloneable接口
- 重写clone()方法
- 访问控制修饰符改为public
- 返回值类型改为当前类类型
- 方法体中调用super.clone(),并返回生成的对象的引用(需要强转)
-
@Override
public Customer clone() throws CloneNotSupportedException {
return (Customer) super.clone();
}
public class Customer implements Cloneable{
private String name;
private int age;
@Override
public Customer clone() throws CloneNotSupportedException {
return (Customer) super.clone();
}
// 。。。
}
public class Test {
public static void main(String[] args) throws Exception{
Customer c1=new Customer("孙悟空",500);
Customer c2=c1.clone(); // 为什么无法调用? 如何才能调用?
// 在java中, == 用于判断2个变量引用的地址是否相等
System.out.println("c1==c2?"+(c1==c2));
c2.setName("猪八戒");
System.out.println("c1.name="+c1.getName());
}
}
-
浅克隆和深克隆
-
当对象关联了另一个对象A时,克隆操作默认克隆的是另一个对象A的地址,会导致克隆后的对象和原对象引用相同的A对象,这种现象称为浅克隆
-
为了规避上述问题,开发者需要在重写clone()方法时,手动对关联的对象进行科隆,保证克隆后的对象关联的也是另一个新对象,这种操作称为深克隆
-
@Override // 深克隆
protected Customer clone() throws CloneNotSupportedException {
Customer c=(Customer) super.clone(); // 浅克隆
Weapon w=c.getWeapon().clone(); // 克隆武器
c.setWeapon(w); // 让c引用新的武器
// c.setWeapon(c.getWeapon().clone());
return c;
}
-
finalize():当垃圾回收器将要回收对象所占内存之前被调用,即当一个对象被虚拟机宣告死亡时会先调用它finalize()方法,一般用于关闭该对象创建的流或释放其他关联的资源。
- 重写finalize方法需要慎重,如果一个对象的finalize方法因为某种原因未执行完毕,则该对象会一直驻留在内存中,不会被垃圾回收器回收
-
getClass():返回对象的实际创建类的类型(Object的运行时类的类型)
-
hashcode():返回对象的哈希码值
- 哈希码值(取值范围广、散列分布)— 取值就是唯一的可以代表地址值
//不同对象的哈希码值不一样
//内存的地址值唯一的
//哈希码值(1.取值范围广(41亿左右)2.散列分布(均匀分布))
//哈希码值的重复概率:1/41亿*1/41亿,小概率事件表示重复的概率几乎不会发生
//哈希码值是唯一的---代表地址值,地址值才唯一的
System.out.println(newObject().hashCode());
//转成十六进制
System.out.println(Integer.toHexString(newObject().hashCode()));
-
toString():返回对象的拼接地址值
- 为了获取对象的属性值对Object类里的toString进行重写
-
equals():判断2个对象是否逻辑相等
-
今天去手机店买手机 -> 华为P40 pro,白色,16GB,128GB硬盘,新的
- 店里有50台库存 -> 50个对象 -> 逻辑上是相等的
-
-
在代码世界,就是这50个对象的关键属性的值都是相等的
-
物理相等:内存地址相等,使用
==
进行判断-
逻辑相等:内存地址相等或者指定的属性值相等,使用
equals()
方法判断 -
在实际开发中,判断2个引用类型的值是否相等,统一使用
equals
方法 -
因此,我们后续自定义的类,都要求重写
equals
方法 -
使用时,需要对方法进行重写
- 判断地址值是否相等
- 判断参数是否为null
- 判断两个对象的类型是否一致
- 比较对象属性值是否相等
-
public class ObjectDemo4{
public static void main(String[] args){
//创建对象
Actor a1=new Actor();
a1.name=null;
a1.age=23;
a1.gender='男';
Actor a2=new Actor();
a2.name=null;
a2.age=23;
a2.gender='男';
//Object里equals方法是根据对象的地址值是否相等来判断对象是否相等
System.out.println(a1.equals(a2));
}
}
classActor{
//属性
String name;
int age;
char gender;
//java自动生成重写equals方法
@Override
public boolean equals(Object o){
if(this==o) return true;
if(o==null||getClass()!=o.getClass()) return false;
Actor actor=(Actor)o;
return age==actor.age&&
gender==actor.gender&&
Objects.equals(name,actor.name);
}
@Override
public int hashCode(){
return Objects.hash(name,age,gender);
}
//重写equals方法
//为了保证判断两个对象是否相等由地址值和属性值综合判定
/*@Override
public boolean equals(Object obj){
//1.判断地址值是否相等
if(this==obj){
return true;
}
//2.判断参数对象是否为null
if(obj==null){
return false;
}
//3.判断两个对象的类型是否一致
//把所有类型不一致的情况去掉了
if(this.getClass()!=obj.getClass()){
return false;
}
//当程序执行到此,两个对象的类型一致,从逻辑上的看的
//逻辑上已经保证类型一致了但是还要保证语法上的对象类型一致
Actor a=(Actor)obj;
//4.比较对象的属性值
//两个对象的年龄是否一致
if(this.age!=a.age){
return false;
}
//两个对象的性别是否一致
if(this.gender!=a.gender){
return false;
}
//判断两个对象的名字是否相等
//根据地址值来判断两个name对象是否相等
//调用的equals方法是String类的重写方法,对地址值和内容来进行比较
if(this.name==a.name||this.name!=null&&this.name.equals(a.name)){
return true;
}
//名字不相等
return false;
}*/
}
String(字符串)
1. 概念
-
Java中所有的字符串直接量都是String类的对象
-
String类提供了一系列用于字符串操作的方法
-
String类底层是由不可改变你的字符串数组来实现数据存储,对象创建完成字后内容无法改变
-
所有的直接量以及常量都是存储在方法去的运行时常量池中,当有多个字符串直接量内容一致时,是共享同一个方法区的常量池信息