思想
- 面向对象的编程思想:领悟认识:短时间难以领悟到的
- 理论学习+后期实践应用【 用对象 】
语法
- 语法的学习:语法是规定,是死的【环环相扣的】
- 围绕着类来学习的:围绕着类,有哪些语法,用法在变化
1初识面向对象
- 面向对象 : 就是一种编程思想
- 面向过程 : 也是一种编程思想
- 最近几天重点:
基于面向对象的编程思想,不断结合,使得语法认知更加透彻,并细致入微总结每一个语法点,关于面向对象的语法,前期需非常努力,后期也会持续加强,但学习时不可以疏忽懈怠。面向对象和面向过程都是软件开发的一种编程思想,要真正的理解一种编程思想,或者说应用在实际的开发设计中,并不是看几本书,听我说几句就能搞定的事情,需要先了解,在实际开发中应用,这样不断的思考分析、积累,从而达到理解。
类与对象
类 :是指描述一类事物,或者看成是一个分类, 例如人类、车类、星球类,
对象 : 是指具体的个体(也叫实例-instance), 例如马云、王石、老郑、马云的迈巴赫、王石的切诺基、你自己的二八自行车、地球、火星等等。
Java语言设计
Java语言设计的思想,希望将现实生活中,对象与对象之间的关系在计算机系统得以体现
构建计算机系统, 用的对象!
百度面向对象
现实世界中,随处可见的一个事物就是对象,对象是事物存在的实体,如人类、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象所属于的某一类事物都是由哪些部分组成的。
通常都会将对象划分为两个部分,即动态部分【行为】与静态部分[描述]。
①静态部分:顾名思义就是不能动的部分,这个部分被称为“属性”,任何对象都会具备其自身属性,如一个人,它包括高矮、胖瘦、性别、年龄等属性。
②动态部分:然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以哭泣、微笑、说话、行走,这些是这个人具备的行为(动态部分),
人类通过探讨对象的属性和观察对象的行为了解对象。、
静态部分:属性
动态部分【行为】:属性
如何设计类[从代码的角度]
如何设计类 |
①java中的类,就是类!用来描述一类事物,任何事物包含:静态属性,动态属性
java中的类就是用来描述一类事物!
②通过设计类,可以用来描述一类事物
③如何设计:
静态属性[描述]:成员变量[成员字段]
动态属性[行为]:方法
设计类,设计模板
class Student{
String name;//静态属性:成员变量:成员字段,
int age;//静态属性:年龄
void eat(){//动态行为
}
}
构造方法
|
- 构造方法的结构和普通方法类似,但是和普通方法完全不同两个代码块;
- 构造方法也是方法,意味着使用了构造方法,方法会执行,也能完成功能
- 构造方法就是一个代码块【就是一个结构 ,构造方法和 字段 方法一样都是一个类中的成员之一】
- 构造方法也该存在于类的结构体中
2.构造方法写法: |
- 构造方法的名字和类名一致【包括大小写完全一致】
- 没有返回值类型
- 构造方法内部不需要返回任何的数据
其他的和普通方法类型 ,可以有修饰(public),可以有形参列表,可以有方法体
1. 类中构造方法特点: |
- 每一个类中都至少有一个构造方法;
- 如果没有看到(显示的),那么存在一个隐式的无参数的构造方法;
- 如果一个类中有显示的构造方法,那么隐式的就不存在了;
2. 验证new Student()就是在调用构造方法? |
- 把隐式的构造方法显示写出来
- 在这个构造方法里面随便写点打印代码
执行new Student(),。。。。
构造方法的作用
① 通过调用构造方法可以创建对象
② 在创建对象的同时给对象的字段赋值
(1)在创建对象的同时给对象的字段赋值--》通过构造方法来完成
5.4 构造方法注意事项
明确: |
- 构造方法(Constructor)和普通方法(Method)是不一样的代码块,只是结构有些类似而已;
- 构造方法也是方法,方法执行,可以写功能代码,执行构造方法能完成一定的功能
构造方法的注意事项 |
- 普通方法可以名字和类名一致,但是不推荐这样,容易混淆;
- 构造方法的调用方式和普通方法不一样
- 把构造方法 Student 写成小写了 student;
普通方法可以名字和类名一致,但是不推荐这样,容易混淆;
构造方法的调用方式和普通方法不一样
注意:到目前为止构造方法的调用方式 : new 构造方法();
因为有返回值类型 void 此方法就是普通方法,只是方法名和类名一样,
容易误导人,千万不要这样写!!!
原因 : 1 如果是构造方法那么首字母应该大写; 2 如果是普通方法应该有返回值类型
普通方法和构造方法是不同的两种结构
- 调用方法不一样
- 普通方法的调用 : 3种
- 类名.方法名+参数列表
- 对象.方法名)
- 直接方法名
---》 不适用于构造方法
- 构造方法的调用 : 1(目前) new Xxx(...);
5.5 构造方法小结
保持面向对象的编程思想[什么是面向对象 ,,,,,,模板---->复印件]
①引入,一系列的认识
②什么是构造方法
③构造方法的特点
④构造方法的使用方式
⑤构造方法的作用
static关键字 静态的 修饰符[类级别的]
1 static引入及修饰内容测试
- 这是从第一次写hello的时候,就见过;
- static 是Java的一个关键字[java里面的关键字 全部小写],也是一个修饰符;
- 可以修饰什么和不可以修饰什么?[下面有很多术语,记住就好]
static是修饰符:可以修饰的内容:及验证 |
目前java 代码中存在的东西 分析
- 可以修饰普通方法
- 可以修饰字段[ 成员字段 ]
- 可以修饰内部类[暂时不了解]
- 不可以修饰外部类
- 不可以修饰局部变量;
- 不可以构造方法
思考:static修饰之后有什么作用 |
3.2 修饰字段:如何访问?
- 有static修饰的字段应该是字段所在类 类名.字段名 进行访问
public static void main(String[] args) {
Student.name = "王歘歘";
System.out.println(Student.name);
}
class Student{
static String name;
}
---------- Java ----------------------------------
王歘歘
输出完成 (耗时 0 秒) - 正常终止
- 没有static 修饰的字段: 字段所在的类的对象:对象名.字段名 进行访问
public static void main(String[] args) {
Student stu = new Student();
stu.name = "歘歘王";
System.out.println(stu.name);
}
class Student{
String name;
}
---------- Java ----------------------------------
歘歘王
输出完成 (耗时 0 秒) - 正常终止
- 注意:非static修饰字段:错误的访问方式
public static void main(String[] args) {
Student.name = "王歘歘";
System.out.println(Student.name);
}
class Student{
String name;
}
3.3 修饰方法:如何使用?
- 有static修饰的方法: 方法所在的 类名.方法名(...);
public static void main(String[] args) {
Student.eat();
}
class Student{
static void eat(){
System.out.println("薯片");
}
}
- 没有static修饰的方法 : 方法所在的类的对象名.方法名(...);
public static void main(String[] args) {
new Student().eat();
}
class Student{
void eat(){
System.out.println("薯片");
}
}
- 注意:非static修饰方法:错误的访问方式
public static void main(String[] args) {
Student.eat();
}
class Student{
void eat(){
System.out.println("薯片");
}
}
3.4 字段:什么时候使用static修饰呢?有什么效果
- 我们在写一个字段的时候,是否应该加static ---》 根据实际情况
- 实际情况:设计一个学生类,其中有name-姓名 字段,是否应该加static 呢? ---》 加与不加的效果
验证使用static修饰字段之后的效果 |
- 效果:加了static修饰的字段:该字段被该类所有对象共享:当一个对象修改了该字段,其他对象使用该字段,都是修改之后的值
cpublic static void main(String[] args) {
Student stu1 = new Student();
stu1.name = "小渣渣";
System.out.println(stu1.name);
Student stu2 = new Student();
stu2.name = "大渣渣";
System.out.println(stu1.name);//大渣渣
System.out.println(stu2.name);
}
class Student{
static String name;
}
实际情况分析:name字段是否应该加上static字段 |
- 结果: Student中的name这样的字段不应该使用static 修饰
- 因为: static修饰的字段会被所有的对象共享,只有一份:而每个学生对象的名字应该是属于自己的,不能被别人修改
思考 : Student(学生类)中哪些字段是应该使用static修饰呢?
班级? 学校?班主任?名族?国籍?性别?教室。。。 ----> X
- 哪些字段应该是static的 [实际开发为准] 例如 :
- int的位数 32 ---》 可以写一个类,里面写一个static修饰的字段 表示位数 Integer.SIZE
class Test{
public static final int SIZE = 32;
}
- 数学上的π -----> Math.PI
- 全球人口数量
- 注:一般都是全局常量( public static final 修饰的变量 )使用居多
3.5 方法:何时使用static修饰方法?
- 目的: 使用static修饰的方法调用方便
- 常见的地方: 一般就是工具方法【关注方法本身的功能】,例如: Arrays中全部都是工具方法(static)
- 最近面向对象语法,我们一般写的方法都写成非静态,除非非得使用static
3.6 static类级别的修饰符
- static类级别的修饰符理解
- static修饰的字段:应该通过类名.字段名访问
- static修饰的字段:应该通过类名.方法,该字段被该类的所有对象共享
- 对象级别
- 非static修饰的字段:对象名.字段名
- 非static修饰的字段及方法,当创建对象时候,独属于每一个对象,没有被该类的所有对象共享
Student stu1 = new Student();
stu1.name = "小花花";
Student stu2 = new Student();
stu2.name = "大花花";
- 静态上下文不予许访问非静态的变量及方法
class _00Hello{
int i = 10;
public static void main(String[] args){
System.out.println(i);//静态的上下文,无法访问非静态的比变量i
eat();//静态的上下文,访问非静态的变量
}
static void sleep(){
eat();//静态的上下文无法访问非静态的方法
}
void eat(){
}
}
- 非静态上下文可以访问静态上下文:
class Student{
static String name;
static void eat(){//类级别
System.out.println("吃学习......");
}
int age;//对象级别
void run(){//对象级别
System.out.println("顺拐.......");
eat();
}
}
3.7 static 小结:
- static修饰符可以修饰什么
- static修饰的字段及方法应该如何访问
- static修饰字段有什么效果
- static修饰方法有什么效果
- 为什么是类级别的修饰符
3.7 变量分类的详解
- 变量分类的解释方式:(不是难点,知道这些属于什么意思)不要背
- 变量分类有哪些?
-
- 成员变量(面向对象也叫字段)
-
静态的[类变量]:通过类名.变量名访问的变量
非静态的[实例变量]:实例即对象:通过对象访问的变量是实例变量
-
-
- 局部变量:不能使用static修饰
-
---------------------------------------------------------------------------------------
- 分类详解:
称呼 位置 是否有static 生命周期(开始) 生命周期(结束)
类变量 类中 √ 类被加载的时候 类被卸载的时候
实例变量 类中 创建对象的时候 对象被销毁
局部变量 方法内部[形式参数,代码块] 方法被调用的时候 方法调用完毕
类被加载------字节码文件-----》加载(放入)------》JVM中
class Test{
public static void main(String[] args){
//创建对象:类和对象
Student stu = new Student();//数据类型,数据,这玩意stu也是局部变量
}
}
class Student{
String name;
int age;
static double PI = 3.14;
void printlength(){
int size = 10;
}
void getNum(int num){//局部变量分析
int sum = 0
int count;
for(int i = 0;i<=num;i++){
if(i%7==0){
sum+=i;
count++;
}
}
}
}
理解:帮助理解以上内容 |
- 类被加载的时候 : 把类的字节码class文件 加载到 JVM中;
- 局部变量的作用 : 一般都是方法中,为了辅助方法完成功能而临时定义的变量;
- 类变量 : 有static修饰的成员变量(字段);
- 实例变量: 没有static修饰的成员变量(字段);
- 以下的说法尽量少用(了解)
类成员 : 静态的字段和方法
实例成员:非静态的字段和方法
class Test{
//如下两个都是成员变量,[分为静态修饰和非静态修饰]
static String name;//类变量:在类加载到JVM的时候就加载好了
int age;//实例变量:在创建对象的时候加载好了
public static void main(String[] args) {
int i = 10;//局部变量:方法调用的过程中临时存在,方法结束局部变量生命周期结束
}
}
了解: |
①static修饰的成员(字段和方法)应该使用类名.成员名访问
②也可以使用对象名.成员名,但是不推荐!!!(编译完毕之后也是类名来访问)
static int a =10;
类名.a
对象名.a (不推荐使用)--》编译完之后 类名.a
- 封装
5.1 理解什么是封装(日常认知)
现实生活中封装概念的引入 |
- 大家想一想生活中封装是什么?包装 :快递 :打包
- 例如: 浩浩去网上买了个充气娃娃{ 需要打包 }安全,隐式 ,保密 扎两针
- 例如: 买了一条狗狗活的:{打包} 准备吃狗肉...打包就需要透气,外界交流
- 必须是你打开:只要有一定权限的人就可以打开
- 台式机电脑:机箱[ 主板 显卡 内存 电源 硬盘。。。]
- 如上示例的共同点总结:
通过封装的操作,可以达到从物理层面控制访问(外面不能轻易访问到里面内容--》这个就是物理层面)
- 那Java程序是如何进行封装呢? 怎么封装上面的机箱呀?
5.2 Java中的封装如何体现
- 程序中一切都是虚幻的:电脑类:伪代码:
class 电脑{
private 主板
public 内存
硬盘
电源
}
- 如何控制程序中的访问 ?
通过给类中的成员(字段,方法,构造方法)添加访问权限来实现访问控制
- 什么是访问权限:
例子:比如做一个系统,不同人登录进去,的访问权限不一样;
- 访问权限修饰符: private < 默认不写(注意不要添加default修饰)< protected < public
private :私有的 最小权限,被它修饰的成员只能够在本类中可以访问到;
public :公共的 最大权限,任何地方和任何人都能访问;
- 测试:变量 age是private修饰的(私有的)只能够在Student本类中可以被访问
class Test{
public static void main(String[] args) {
int age = new Student().age;
}
}
class Student{
private int age = 10;//私有化的只能本类中可以访问
}
---------- Javac ----------
Test.java:3: 错误: age可以在Student中访问private
int age = new Student().age; ^
1 个错误
输出完成 (耗时 0 秒) - 正常终止
- 为什么需要将字段私有化起来: 安全
5.3封装的步骤
- 上面的代码把name age 私有化 [提供private 修饰 ]之后就不能够操作了,
- 怎么去赋值和取值呢?提供setget方法
- 提供一个无参数的构造方法:标准的javaBean
/*
设计方法存值取值
public 需要,给别人访问的
static 不需要:修饰方法,字段也需要静态修饰,静态修饰的字段被该类的所有对象共享
返回值:存值void 不需要返回值,取值对应字段类型
方法名字:存值setName 取值getName : 特殊情况 布尔类型的字段get 变 is
参数:存值对应字段类型,取值不需要参数
*/
class Student{
private String name;
private int age;
private boolean sex;
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
public void setAge(int a){
age = a;
}
public int getAge(){
return age;
}
public void setSex(boolean s){
sex = s;
}
public boolean isSex(){
return sex;
}
}
5.3 封装小结
- 封装的意识
- 在Java 中的体现及步骤
- 把类中的字段私有化;
- 给每一个字段都提供一组getter setter方法 (方法的规范写法);setXxx
在测试类中尝试创建对象,并通过调用getter setter方法完成 对字段的赋值和取值;
- 提供一个无参数的构造方法
- 思考:
- 能否把一个字段的get 和set方法写成一个方法
-
- 不可取(比如 当我只是取值的时候,还需要传入参数,这不好)
-
- 一个类中的多个字段的赋值方法 写成一个方法
-
- 不可取 耦合度太高(万一我们只想给某一个字段赋值)
-
- 单一职能原则:功能最小化,不要想着一个方法写完所有的功能
- 给对象的字段赋值 一共有哪些方式:
- 直接访问字段赋值 标准java类 X 字段一般都会给私有化(私有化访问不到);
- 通过构造方法赋值 只能够创建对象的时候赋初始值
上面的代码 不是把“小李”修改成“小李飞刀”,而是重新创建对象;
- 通过setXxx方法赋值 更灵活;
setXxx 这么好是否就可以不要构造方法了呢?
两者不冲突,一般可以在创建的时候赋值,也可以后面进行修改
- JavaBean (就是一个标准的Java类):-->(就业班才讲)
- 字段必须私有化
- 给每一个字段提供合理的getter setter方法
- 必须有一个公共的无参数的构造方法;
- this
6.1 this引入
class Test{
public static void main(String[] args) {
Student stu = new Student();
stu.setName("小东西");
System.out.println(stu.getName());
}
}
class Student{
private String name;
private int age;
public void setName(String name){//命名应写成 name见名知意思,但写完之后,存取不到值,堆栈分析,变量使用就近原则
name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
age = age;
}
public int getAge(){
return age;
}
}
- 尝试使用this 解决问题
6.2 this介绍
- this的概念:this指代当前对象,持有当前对象的地址
- 如何判断this指代的是哪个对象
- 官方:this所在的函数,正在被谁调用this就指代谁
- 民间 :this当前被对象持有,this就指代谁,模板---->复印件
- 测试this持有当前对象地址
class Test{
/*
1.官方 :this所在的函数,正在被谁调用this就指代谁
2.理解 :this表示的是当前对象,可看成this持有当前对象的地址值;
3.民间 :this当前被哪个对象持有,this就指代谁,模板---->复印件【复印件中包含 this,this指代当前复印件即对象】
*/
public static void main(String[] args) {
/*this表示的是当前对象,可看成this持有当前对象的地址值; this存在于该对象复印件中,所以this指代当前对象*/
Student stu1 = new Student();
System.out.println("this所在函数stu1=" + stu1);
stu1.eat();//1. this所在函数正在被谁调用this就指代谁: this指代stu
//this指代当前对象,换了其他对象,this代表的就是其对象了
Student stu2 = new Student();
System.out.println("this所在函数stu2=" + stu2);
stu2.eat();//1. this所在函数正在被谁调用this就指代谁: this指代stu
}
}
class Student{
void eat(){
System.out.println("this所在函数this=" + this);
}
}
---------- Java --------------------------------------------------------------------
this所在函数stu=Student@15db9742
this所在函数this=Student@15db9742
this所在函数stu=Student@6d06d69c
this所在函数this=Student@6d06d69c
输出完成 (耗时 0 秒) - 正常终止
- this持有当前的对象地址 : this应该在类设计的是时候使用
- this不能写在静态的方法中 : 无法从静态上下文中引用非静态 变量 this
- static类级别
- this对象级别
6.3 this使用场景
- 解决局部变量和成员变量的二义性 --- get set 方法中的应用[在get/set可以写this]
- 作为返回值返回 : this持有对象地址,表示该类的一个对象即是一个数据
- 作为参数传递
- 本类中构造方法之间的相互调用
6.4 this小结
- this是是什么,this是的概念
- 怎么判断this指的哪个对象
- this用途:
- 解决局部变量和成员变量的二义性--》注意 set/get方法 构造方法
- this作为参数传递,this作为返回值
- 在本类之间 ,构造方法之间的相互调用 this()调用无参数的构造方法,this(...)可以添加参数,表示调用有参数的构造方法
继承
继承概念的引入
- 专业解释:
- 泛华:在多个子类的基础上面抽取共有属性的行为到一个父类中去
- 特化:在一个父类的基础上拓展子类特有的属性和行为,生成一个新的子类
- 原则:父类存放共性,子类存放特性
- 代码理解:
- 三个类都有重复的代码,可以把这部分内容 抽出去,抽出去放到另外一个类里面;
- 上面的类我们叫做 父类(超类,基类,根类)
- 下面的3个类和上面的类需要发生一点关系【继承】
- 下面的类我们叫做 子类(派生类,拓展类)
- 提取好处 : 提高了代码的复用性
2.2 Java中类继承的基本语法
- Java类中的继承的语法格式:
class Animal{}
class Person extends Animal{} //目标就是为了继承到Animal,这个类型
A 就是B的父类; B是A的子类
------------------------------------------------------------------------------
- 没有导包Arrays:
- class Tools extends java.util.Arrays{ }
- 导包了Arrays
- class Tools extends Arrays{ }
- 验证:子类中是否可以继承到父类中的东西(通过创建子类对象来操作从父类继承的东西)
class Animal{
String name;
void eat(){
System.out.println("吃实物");
}
}
class Person extends Animal{
}
class Pig extends Animal{
}
测试类:
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.name = "人胖";
System.out.println(person.name);
Pig pig = new Pig();
pig.eat();
}
}
2.3 子类可以从父类继承哪些成员?
- 思考 : 一个父类中可能有哪些? 字段 方法 构造方法
- 思考 : 可能还和访问权限有关 private public
- 验证 :非私有的字段 和方法 可以被继承到(暂时这样记忆-主要是从是否可以访问的层面考虑)
- 构造方法不能够被继承:java规定
- 子类可以继承到父类的特性class MyFrame extends java.awt.Frame{}
class Person extends Animal{
Animal(){};
}
---------- Javac ----------
Test.java:20: 错误: 方法声明无效; 需要返回类型
Animal(){};
^
1 个错误
输出完成 (耗时 2 秒) - 正常终止
2.4 Java中类的继承特点
- Java中类的继承只能够是单继承
- 可以支持多重继承
- 每一个类都有一个直接父类,如果没有看到显示的继承代码,那么就隐式继承就Object
2.5 继承总结
- 继承的概念引入
- 继承的基本语法
- 继承到父类的那些东西
- 非私有的字段及方法
- 父类特性
- 继承的特点
- 单继承
- 多重继承
- 没有显示的继承,那么隐式的继承Object
- 方法覆写(覆盖,重写,Override)
3.1 为什么需要方法覆写
- 父类中有一个walk方法,每个子类都应该有
- new Person().move();
- new Snak().move();
- 实际情况
- 不同的子类对于同一个移动的方法,表现形式不一样
- 补充:子类的动态描述父类的动态描述不一致
- 怎么办
- 把父类的方法拷贝到子类中,修改方法体,功能重新实现【覆盖,覆写Override】
3.2 方法覆写的基本语法
- 明确为什么需要复写:当父类的方法不满足子类的需求的时候,需要覆写
- 基本语法:直接将父类中需要覆写的方法复制放入子类,修改方法体
- 子类方法是否在覆写父类的方法,可以通过注解@Override验证
- 是覆写:编译通过
- 不是覆写:编译报错
- 注解理解
- 注解:跟注释很类似
- 注释:给程序员看的
- 注解:给java程序看的
class Animal{
void move(){
System.out.println("移动");
}
}
class Person extends Animal{
void move(){//复制父类方法,方法体功能语句重新实现
System.out.println("走动");
}
}
3.3 方法覆写的细节
- 方法的覆写语法细节:
- 保证子类方法和父类方法的方法签名(方法名+参数列表)一致;
- 访问权限 : 子类方法的访问权限(修饰符)不能够比父类方法的访问权限更低;
- static 方法不能够被覆写
- 返回值类型 : 子类方法的返回值类型可以是父类方法的返回值类型的子类或者相等
问题代码: int long根本不是类,int也不是long的子类
- 方法主体 : 方法覆写,子类方法和父类方法主体是否可以一样, 可以! 但是没有什么用!
- 方法覆写语法细节示例
3.4 方法覆写总结
- 为什么需要方法复写
- 当父类的方法不满足子类的需求的时候需要复写
- 方法复写的基本语法[ 最常用 ]
- 复制父类的方法到子类中,之后修改复制到子类中的方法体
- 是否是覆写可以通过注解@Override 写在子类被覆写的方法头,
- 是覆写编译通过
- 不是覆写编译报错
- 方法复写的细节
- Object类(及方法覆写的应用)
4.0 Object类引入【所有类的根类】
- 每一个类都有一个直接父类,如果没有看到显示的继承代码,那么就隐式继承就Object
- 理解:Object是每一个类的,直接父类或者间接父类
- Object所有类的根类,是一个非常重要的类,所有类的重要的公共的静态属性,及动态行为[方法]都被提取到了Object
- 结论:Object这个类必须要学习掌握
- 面试:Object里面有哪些方法可以覆写,以及有什么意义!
4.1 认识Object类
- 类 Object 是类层次结构的根类,每个类都使用 Object 作为超类。[备注:接口没有关系]
- 所有对象[包括数组]都实现这个类的方法 : 所有的对象[数组]都可以调用到Object中的方法;
- int[] arr = new int[10];//arr数组,arr变量,arr对象
- arr可不可以看成是一个对象?
- int[]类型引用类型
- 创建一个数组通过new 复制一份
- 实现了Object 是类
- 示例:
- Student s = new Student();
s.hashCode(); 可以的
- String s2 = “等等”;
s2.hashCode();可以的
- int[] arr = new int[6];
arr.hashCode();可以的
- int i = 5;//基本类型数据不是对象
i.hashCode();//不可以的
4.2 介绍Object类里面的方法
- String toString() 返回调用此方法的当前对象的字符串表示形式(把当前对象转成字符串)
- boolean equals(Object obj) 比较两个对象是否相等(比较调用此方法的对象是否和传入的obj”相等”)
- int hashCode() 通过对象结合算法得到一个int值
- Class<?> getClass() 返回此 Object 的运行时类(获得一个对象的真正的类型)
4.3 覆写Object中的方法-toString
- String toString() 返回调用此方法的当前对象的字符串表示形式[把当前对象转成字符串]
- 明确什么是对象描述:静态描述,姓名 年龄 ........
- 实际打印地址值:不符合对于对象的描述
- 暂时记住:打印语句打印对象,实际在调用父类toString方法,打印的对象描述,覆写完成分析怎么调用的
- 父类toString方法返回结果,不符合子类需要打印对象描述的需求,所以覆写toString方法
class Test {
public static void main(String[] args) {
Student stu = new Student("小花花",18);
//System.out.println(stu);//覆写前:Student@15db9742
System.out.println(stu);//覆写后:小花花 - 18
}
}
class Student{
String name;
int age;
Student(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name + " - " +age;
}
}
- 覆写toString方法的意义及什么时候需要覆写toString
- 意义:自定类创建的对象可以准确的打印对象描述
- 什么时候需要覆写:自定义类需要打印对象描述的时候
- 了解:如果使用java中写好的类创建对象,打印的不是地址值,说明该类已经覆写过了toString
- 通过分析打印语(System.out.println(stu))句源码追踪分析打印对象,怎么使用的Object类中的toString方法
- 分析原来怎么会打印地址值
- 覆写之后为什么打印的是覆写后的对象描述:就近原则使用的是自己的toString
- 注意:过程会存在以后知识点,认真听分析:重在理解
4.4 Object中的equals方法使用分析
- equals方法使用分析
- 明确:boolean equals(Object obj) 比较两个对象是否相等(比较调用此方法的对象是否和传入的obj”相等”)
- equals 方法使用,代码示例:
class Test {
public static void main(String[] args) {
Student stu1 = new Student("小花花",18);
Student stu2 = new Student("小花花",18);
boolean result = stu1.equals(stu2);
System.out.println(result);//false
}
}
class Student{
String name;
int age;
Student(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name + " - " +age;
}
}
- 如上代码红色示例,比较结果为false
- 比较结果为false的原因分析:实际Object中方法使用的是==比较:比较的是地址值!
- 现实生活比较对象,姓名 年龄 身份证号,一样,即应该是同一个对象,不因为地址不同,就不是同一个人
- 在java代码中:应该比较的是静态属性是否一致,如果一致则应该是同一个对象
- Object中equals方法比较对象地址,不符合现实生活中比较对象的规则!java代码的对象比较,因该是静态属性的比较,父类Object中equals方法比较对象:不满足子类对象比较静态属性的需求,需要覆写
4.5覆写Object中的equals方法
版本一实现
- boolean result = stu1.equals(stu2);
- 分析:应该是调用方法的对象stu1与传入的对象stu2比较:比较的是静态属性
public boolean equals(Object obj){
if(this.name==obje.name&&this.age = age){
return true;
}else{
return false;
}
}
---------- Javac ----------
Test.java:18: 错误: 找不到符号
this.name==obj.name&&this.age == obj.age;
^ ^
符号: 变量 name
位置: 类型为Object的变量 obj编译器认为 :obj
- obj编译器只看类型不看值:obj为Object类型,没有name,age属性:
- 但是我们知道obj变量中装的Student对象
- 怎么办:把obj 转成Student [还原它的真实类型]
版本一完善 :版本二实现
public boolean equals(Object obj){
Student stu = (Student)obj;
if(this.name==stu.name&&this.age = stu.age){
return true;
}else{
return false;
}
}
版本二完善 :版本三实现
- this.name Student中的name字段是String类型,有可能会比较引用地址,【有风险】
- name字段是String类型的对象,对象的比较应该使用equals比较
public boolean equals(Object obj){
Student stu = (Student)obj;
if(this.name.equals(stu.name)&&this.age = stu.age){
return true;
}else{
return false;
}
}
版本三完善 :
- 上面if中 this.name.equals(stu.name)&&this.age==stu.age 本身结果就是布尔类型的值,没必要写if结构
public boolean equals(Object obj){
Student stu = (Student)obj;
return this.name.equals(stu.name)&&this.age = stu.age;
}
- 什么时候需要覆写Object中的equals方法,及覆写的意义
- 什么时候需要覆写自定义类对象,相互之间需要比较对象的静态属性的时候!
- 覆写的意义:能够需求,正确的比较对象,静态属性
- 小结toString equals,当真正覆写的时候,注意,根据需要用,哪些字段!
4.6 == 和 equals区别[面试题]
- == 和 equals 都是比较是否相等,请问它们到底有什么区别呢?
相等 : a 传统的理解一般都是数字值是否相等;
b 在程序中任何东西都是数据,都会比较是否相等[ 对象 ]
- == 比较运算符
- 基本数据类型变量: 比较的就是值是否相等;
- 引用数据类型变量: 比较的是对象的地址是否一样;(排除特殊 String)
- equals 方法[最初定义在根类Object中的,比较对象是否相等]方法里面 ==
- 基本数据类型 : 不能够使用! 基本数据类型不是对象,不能够调用Object中的方法
- 引用数据类型 : 但是在Object的源码中定义的就是 == 进行比较比较
- 定义好的类没有覆写过equals方法,则会直接调用到了Object中的equals方法,那么本质还是在使用==比较
- 在实际开发中,自定义类:一般比较对象,都是通过对象的属性值进行比较,所以自定义类,会经常覆在自定义的类中写Object中的此方法,把自己的比较规则写在方法里面;
- 覆写equals方法的意义:定义类,覆写equals方法,自己制定规则,比较自定义类对象的静态属性
小结 : 比较基本数据类型:== 比较对象用 equals方法
- 访问权限修饰符
5.1 什么是权限修饰符及作用
- 权限修饰符 : private < 默认不写(注意不要添加default修饰)< protected < public
- 作用 : 主要是控制类以及类中成员的访问权限
5.2 测试修饰内容
- 要知道哪些东西能被修饰:主要是修饰类中的成员(字段 方法 构造方法, 内部类);
- public 默认 ①可以修饰类[内部类 和 外部类]
- private protected ①不能够修饰类外部类
- 都不能够修饰局部变量
super
1 Super引入前示例
- 假设关于继承的理解(示例):
- 目前理解的子类可以继承父类哪些东西 : 非私有的字段和方法【主要是从访问权限的角度,局限性】
- 看示例:做学生管理系统,需要登陆的功能: 涉及 ,学生账号,老师账号
都是账号有共同属性 account password 但是学生账号和老师账号都有独有的属性行为
- 类的设计
- 设计一个用户类User : 包含: 用户名 密码 字段
- 让学生类和老师类继承 User用户类
- 规范写法:User类中的用户名及密码字段应该私有化提供get set方法
- 问题:父类User中的字段私有化,子类学生类和老师类能够继承到用户名和密码吗?
- 从目前理解(主要是从访问权限来看),子类是继承不到私有成员的;
- 是否应该在子类中再定义用户名和密码字段呢? 不应该!
- 结论:子类对象中应该没有用户字段及密码字段可以存值
- 类设计: 账号类User,学生账号类StudentUser,老师账号类TeacherUser
class User{//账号类
private String account;
private String password;
public void setAccount(String account){
this.account = account;
}
public String getAccount(){
return this.account;
}
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return this.password;
}
}
class StudentUser extends User{//学生账号类 extends 账号类
}
class TeacherUser extends User{//老师账号类 extends 账号类
}
- 测试类
//测试类
class Test {
public static void main(String[] args) {
StudentUser stu = new StudentUser();
stu.setAccount("嚣张");
stu.setPassword("123456");
System.out.println("账号:"+stu.getAccount()+", 密码:"+stu.getPassword());
}
}
---------- Java ----------
账号:嚣张, 密码:123456
输入完成 (耗时0秒) - 正常终止
- 分析:发现StudentUser类,虽然没有继承到字段,但是还是在通过set get方法正常的存值取值,感觉还是用到User类中的account password字段的,为什么且听super分析
2.2 回顾this
- this的概念:this表示当前对象,持有当前对象的地址
- 判断this当前对象是谁?
- 官方:this所在的函数正在被谁调用,this就指代谁
- 民间:this当前被哪个对象持有this就指代谁
- this的使用场景
- 通过this访问当前对象中的成员(字段,方法);区分成员变量与局部变量的二义性
- 把this(当前对象)看成是一个数据, 就可以作为值返回,作为参数传递...
- 使用场景-2 : 本类中构造方法的之间的方法体第一句相互调用;
- this(); 调用本类中无参数的构造方法;
- this(123); 调用本类中具有一个int参数的构造方法;
2.3 什么是super
- 什么是Super代码分析示例
//测试类
class Test {
public static void main(String[] args) {
StudentUser stu = new StudentUser();
stu.eat("大花花");
}
}
class User{
String name = "小花花";
}
class StudentUser extends User{
String name = "中花花";
void eat(String name){
System.out.println("name = "+name);
System.out.println("this.name = "+this.name);
System.out.println("super.name = "+super.name);
}
}
- super的概念:在子类中表示父类的对象
- 区别this:super不持有父类对象地址
//子类方法测试打印super
System.out.println(super);
Test.java:17: 错误: 需要';'
System.out.println(super);
^
Test.java:19: 错误: 解析时已到达文件结尾
}
^
4 个错误
输出完成 (耗时 0 秒) - 正常终止
2.4 super的使用场景
- 前提:super访问父类的成员,都必须是在有访问权限的条件之下;
- super访问父类对象中的字段 及 普通方法;
class User{//父类User
String name = "小花花";
void login(){
System.out.println("User login");
}
}
class StudentUser extends User{//子类 StudentUser
String name = "中花花";
void eat(String name){
System.out.println("super.name = "+super.name);//super访问父类字段
super.login();//super访问父类普通方法
System.out.println("name = "+name);
System.out.println("this.name = "+this.name);
}
}
class Test {//有主方法的测试类Test
public static void main(String[] args) {
StudentUser stu = new StudentUser();
stu.eat("大花花");
}
}
---------- Java ------------------------------------------------------
super.name = 小花花
User login
name = 大花花
this.name = 中花花
输出完成 (耗时 0 秒) - 正常终止
- 在子类的构造方法体第一句访问父类的构造方法; 最常用的!!!!!!!!!!!!
- super(); 调用父类无参数的构造方法;
- super(123); 调用父类中具有一个int参数的构造方法;
2.5 super的特殊使用场景及分析
- 特殊使用场景 :在子类的构造方法第一句,
- 如果没有显示的写出对于父类构造方法的调用,那么会隐式的调用父类的无参数的构造方法!
- 如果有显示的写出对于父类构造方法的调用,那么会隐式的调用父类的无参数的构造方法,就不存在了!
- 特殊使用场景结论:子类的构造方法中一定会调用到父类的构造方法
- 特殊使用场景测试
class User{
User(){
System.out.println("隐式无参父类User");
}
User(String name){
System.out.println("显示有参式父类User");
}
}
class StudentUser extends User{
StudentUser(){//隐式调用父类的无参数的构造方法
System.out.println("隐式子类StudentUser");
}
StudentUser(String name){//显示的写出隐式的调用就存在了
super(name);
System.out.println("显示子类有参StudentUser");
}
}
//测试类
class Test {
public static void main(String[] args) {
System.out.println("----------隐式父类无参数构造方法调用---------");
new StudentUser();
System.out.println("----------显式父类有参数构造方法调用----------");
new StudentUser("小王八");
}
}
- super特殊用途分析:无论如何,子类的构造方法一定会存在对于父类构造方法的调用【难点:重在理解】
- 私有化字段在子类getset可以用到的原因
- javaBean为什么一定要提供一个无参数的构造方法
- 为什么子类可以继承父类的东西寄特性
2.6 super小结
- super概念
- super的作用
- super的特殊用途
- super的特殊用途分析
- 多态(要点,难点)
3.1 多态的引入
- 简单理解一种事物的多种形态
- 示例:
- 今天晚上请大家吃大餐 : 思想上的大餐 , 凉开水
- 同学们准备买一辆车: 宾利 兰博基尼 柯塞尼格
- 同学们要上天 : 坐飞机,
什么是多态
- 一个人就是一个动物:
- Animal aml = new Person();//一个动物变量中,可能存放子类对象的多种可能
- 理解:使用aml:编译是看的是Animal类型,运行时看的是实际存放的对象[真实类型]
- 官方概念:编译时跟运行时类型不一致就产生了多态
- 民间理解:父类类型的变量,存放子类类型的对象,可能存放子类类型的对象有多种可能
- 多态存在的前提:必须有继承关系
3.3 多态方法调用编译运行过程[重点]
class Animal{
void eat(){
System.out.println(“食物........”);
}
}
class Person extends Animal{
}
//----------------------------------测试类-----------------------
class Test {
public static void main(String[] args) {
Animal aml = new Person();
aml.eat();
}
}
- 上面两句代码的编译,运行过程:
- 编译时 :
- aml 编译时,看的是父类类型,会在父类类型中eat方法
- 如果没有找到,会继续向上找[aml编译时父类类型]
- 找到:编译通过
- 找不到:编译报错
- 注意:是不会向下找的[aml编译时子类类型]
- 运行时 :
- 先到运行时类型[Person]中找eat方法,
- 如果找到:就执行,
- 没找到:向上到父类中找并执行
- 先到运行时类型[Person]中找eat方法,
- 思考 : 有没有可能编译通过了,而运行找不到方法... 不可能!
3.4 编译时与运行时的几种情况分析
- 父类中有一个方法,子类覆写了
- 父类中有一个方法,子类没有
- 父类中没有,子类有一个方法
- 父类子类都没有
----------- 上面都是实例方法,下面来一个静态方法---------------------------------
- 静态方法
- 字段没有覆写一说
分析:
- 实际开发中一般不会再子类中定义一个和父类同名的字段,
- 如果是有这样的情况存在,
- 如果编译时类型父类的类型,取值是父类里面字段的值;
- 如果编译时类型子类的类型,取值是子类里面字段的值;
3.5 多态方法调用以及参数传递应用示例[重点]
class Dog{//父类类型Dog
void eat(){
System.out.println("吃食物");
}
}
class DDog extends Dog{//子类类型DDog
void eat(){
System.out.println("哈根达斯");
}
}
class XDog extends Dog{//子类类型XDog
void eat(){
System.out.println("吃牛排喝红酒");
}
}
class Person{//人类:定义喂狗方法
void feedDog(Dog dog){
dog.eat();
}
}
//------------------------------测试类-----------------------------------
class Test {
public static void main(String[] args) {
Dog ddog = new DDog();
XDog xdog = new XDog();
Person pson = new Person();
pson.feedDog(ddog);
pson.feedDog(xdog);
}
}
3.6 多态体现的几种情况
- 如上代码多态的体现的本质:都是父类类型的变量存放子类类型的对象
- Dog dog = new XDog();//核心本质
- 方法参数传递:方法形参父类类型,允许传子类类型对象
-
- Dog dog = new XDog();
- XDog xdog = new XDog();
- void feedDog(Dog dog){ }//此方法运行传递上面两个参数dog 或者 xdog : 本质传递的都是子类对象
-
- 方法返回值
Dog getDog(){//此方法返回值类型为父类类型Dog
return new XDog();//允许返回子类类型
}
思考:方法内部返回值的类型一定是,方法返回值位置指定的类型么?
- 多态的好处:屏蔽了不同子类之间实现的差异
- 加强面向对象编程思想:
- 此处体现java语言设计是想,希望将现实生活中的对象与对象之间的关系在计算机系统得以体现
3.7 多态小结
- 多态的概念
- 编译时运行时过程
- 多态的用途【多态的方法参数传递】
- 结合面向对象编程思想及执行流程分析
- 多态在代码中如何体现的
- 多态的好处
- 加强面向对象编程思想的认识
- 引用类型转换
4.1 引用类型转换引入
class Cat{
void eat(){}
}
class TomCat extends Cat{
void say(){}
}
class CoffeeCat extends Cat{
void drink(){}
}
//测试类
class Test {
public static void main(String[] args) {
Cat cat = new Tomcat();
cat.drink();//编译报错
}
}
- 分析:类设计:提取公共属性,子类存在特有属性
- 示例:猫[Cat]都会吃,但是汤姆猫[TomCat]会说话,咖啡猫[CoffeeCat]会喝咖啡
- 多态使用存在可能:
- Cat cat = new TomCat();
- cat.say();//编译时报错:say动态属性在,Cat中不存在
4.2 为什么需要引用数据类型转换
- 如上示例:明知cat里面存放的是Tomcat,但是因为多态编译不能通过,不能使用,需要转换成Tomcat真实类型,即可以使用
4.3引用数据类型转换的两种情况
- 明确:数据类型转换存在两种,情况,大转小:小转大
- 子类类型转父类类型:小转大
Cat cat = new TomCat();
double d = 1;
- 父类类型转子类类型:大转小
TomCat tc =(TomCat)cat;
- 在引用数据类型中:父类是较大的数据类型,子类是较小的数据类型
4.4 引用数据类型转换的注意事项
class Cat{
void eat(){}
}
class TomCat extends Cat{
void say(){}
}
class CoffeeCat extends Cat{
void drink(){}
}
//测试类
class Test {
public static void main(String[] args) {
Cat cat = new Tomcat();
CoffeeCat cc = (CoffeeCat)cat;
cc.drink();
}
}
- 如上代码示例分析;
- cat可能是传来的参数:在使用的时候不知道存放的是Tomcat,误以为存的是CoffeeCat类型
- 红色代码使用多态:绿色代码引用类型数据转换:cc.drink();
- 编译只看类型不看值,如上代码编译都不会有问题!
- 但是:运行时反应的是真实类型,绿色代码等于要将TomCat 变成 CoffeCat 显然不行!
- 因此引用数据类型转换,最好在转换之前先判断类型在转换
- 判断类型的方式
- 获得运行时类型 Object 中getClass();方法
- 类型判断运算符 instanceof
- 判断类型示例
- 获得运行时类型 Object 中getClass();方法
class Test {
public static void main(String[] args) {
Cat cat = new TomCat();
String name = cat.getClass().getName();//获取到类型的名字String类型的值
if(name.equals("CoffeeCat")){//比较是否羽CoffeeCat字符串一致
CoffeeCat cc = (CoffeeCat)cat;
cc.drink();
}else{
System.out.println("友好提示:小哥哥类型错了");
}
}
}
-
- 类型判断运算符 instanceof
//测试类
class Test {
public static void main(String[] args) {
Cat cat = new TomCat();
if(cat instanceof CoffeeCat){
CoffeeCat cc = (CoffeeCat)cat;
}else{
System.out.println("友情提示:小姐姐你的类型错了");
}
}
}
- instanceof运算符
Systme.out.println(cat instanceof Cat);//true
Systme.out.println(cat instanceof TomCat);//true
Systme.out.println(cat instanceof Object);//true
Systme.out.println(cat instanceof CoffeeCat);//false
System.out.println(tom instanceof CoffeeCat);编译报错,不存在继承关系,不兼容,完全相关类型:编译器只看类型不看值
Systme.out.println(cat instanceof String);//编译报错,不存在继承关系,不兼容,完全相关类型:编译器只看类型不看值
4.5引用数据类型转换小结
- 为什么需要引用数据类型转
- 明知道多态父类类型装的是子类对象,但是子类特性,父类对象访问,编译报错,需要转换成真实类型
- Cat cat = new TomCat(); cat.say();//父类Cat中没有say属性 编译报错
- 数据类型转换的两种情况
- 大赚小 TomCat tc = (TomCat)cat;
- 小转大 Cat cat = new TomCat();
- 父类大子类小 : 父类类型兼容子类类型
- 数据类型转换的注意事项
- 在转换之前要进行类型判断
- 两种判断方式
- instanceof运算符的运用
- 只看类型不看值,不存在继承关系的,编译不通过
- final
5.1 final是什么
- final : Java中的一个关键字,修饰符:表示的意思:最终的,不可变的,不可拓展的!
- 如何学习关键字修饰符
- 关键字的含义
- 可以修饰什么东西
- 修饰之后有什么效果
5.2 final可以修饰的东西
- 外部类:可以
- 普通方法:可以
- 成员字段:可以
- 局部变量:可以
- 内部类:可以 [ 暂时不学 ]
- 构造方法:不可以
5.3 final修饰类的效果
- final修饰类:最终类,不可拓展的类,太监类 :
- 比如说: String类 Integer等包装类 是使用final修饰的;
final class Cat{
}
class TomCat extends Cat{
}
---------- Javac ----------
Test.java:10: 错误: 无法从最终Cat进行继承
class TomCat extends Cat{
^
1 个错误
输出完成 (耗时 0 秒) - 正常终止
- 思考:final修饰的类有不有父类呢
5.4 final 修饰普通方法的效果
- final修饰普通方法:最终的方法,不可拓展的方法:
class Cat{
final void eat(){}
}
class TomCat extends Cat{
@Override
void say(){}
}
---------- Javac ----------
Test.java:12: 错误: 方法不会覆盖或实现超类型的方法
@Override
^
1 个错误
输出完成 (耗时 0 秒) - 正常终止
- 目前不能被覆写的方法 有哪些?
- 使用final修饰的方法
- 使用static修饰的方法
- 使用private修饰的方法
5.5 final 修饰变量
- final修饰变量:表示最终的变量 :
//测试类
class Test {
final static int i = 10;
public static void main(String[] args) {
final int j = 20;
i = 30;
j = 40;
}
}
- final 修饰变量一般使用 public static final double PI = 3.14159265; 构成类中的全局常量仅供使用
- final修饰变量拓展及堆栈分析
//测试类
class Test {
public static void main(String[] args) {
final Student stu = new Student();
stu.name = "小王";//可以因为修饰的不是name字段
System.out.println(stu.name);
stu = new Student();//不可以因为修饰的是stu变量
}
}
---------- Javac ----------
Test.java:7: 错误: 无法为最终变量stu分配值
stu = new Student();//不可以因为修饰的是stu变量
^
1 个错误
输出完成 (耗时 0 秒) - 正常终止
5.6 final小结
- final关键字修饰符最终的不可拓展的不可变的
- final可以修饰那些内容
- final修饰类的效果
- final修饰方法的效果
- final 修饰变量的效果
- final修饰变量的拓展分析
- 枚举(掌握)
4.1 枚举的引入:
- 枚举:java类比较类似的结构:
- 核心解决的问题:在java中,有一种数据类型,只存在固定的几个值
- 什么是一种数据类型只存在固定的几个值
- 例如 :String str = "1" "5" "就" ...... 每一个字符串都是String 类型的一个值:String 只有固定的几个值嘛?
- 学习过类型哪些之后固定的几个值: boolean 单例模式
- 设计一个人类,性别字段应该只有男女,所以该字段应该是只有固定的两个值
- 设计思路分析
- 思路分析:String ? int ? boolean ?都不好
- 自己设计一个Sex类就是一个数据类型,一个对象就是一个值:
- 所以只要对象创建的个数是固定的不变的:自己设计的类型的值就是固定的
- 单利模式变多利模式【特殊写法看懂】
- Sex类设计实现版本1
- 构造方法私有化
- public static final修饰,public 全局可以防范,static类名.字段名访问,final修饰不能修改
class Sex{
private Sex(){};
public final static Sex MAN = new Sex();
public final static Sex WOMAN = new Sex();
}
- Sex类设计实现版本1测试
//测试类
class Test {
public static void main(String[] args) {
Sex man1 = Sex.MAN;
Sex man2 = Sex.MAN;
System.out.println(man1);
System.out.println(man2);
Sex woman1 = Sex.WOMAN;
Sex woman2 = Sex.WOMAN;
System.out.println(woman1);
System.out.println(woman2);
}
}
---------- Java ----------
Sex@15db9742
Sex@15db9742
Sex@6d06d69c
Sex@6d06d69c
输出完成 (耗时 0 秒) - 正常终止
结果:确保了:值固定个数,但是打印结果为地址值,不够直观
- 方案2:解决方法1打印不够直观
- 给每一个Sex对象里面内置一个String字段,用来存放保存性别的中文描述;
- 在创建对象的时候,把中文写进去,toString里面返回对象中的中文描述;
class Sex{
String name;//描述性别值的一个字段
private Sex(){};//
public final static Sex MAN = new Sex("男");
public final static Sex WOMAN = new Sex("女汉字");
Sex(String name){
this.name = name;
}
//打印对象描述覆写toString方法
public String toString(){
return this.name;
}
}
4.2 什么是枚举
- 枚举看成是 一个和 类 非常类似的新结构;
- 枚举的出现解决了问题: 很轻松设计一种类型,让它的值只有固定个数,用于像性别这样的数据
4.3 枚举的使用场景
- 性别, 星期,季节,VIP等级,段位。。。。
4.4 枚举的基本语法
- 声明语法:
enum 枚举类名字{
字段
方法
构造方法 - 枚举中的构造方法默认都是private修饰,不能够是public
}
- 一般枚举类型也是写在一个Java文件中,编译完毕也会生成字节码文件
- 每一个自定义的枚举类型都(隐式的)拓展至 Enum 类,因此我们的枚举对象可以调用到Enum中的方法的(看API )
- 自己百度测试switch使用枚举 以及回顾switch相关的语法
4.5 枚举示例代码及拓展
- 示例代码: 设计一个性别的枚举类型
enum Sex{
男,女
}
- 上面代码中 男 女 就是Sex类型的两个对象
//测试类
class Test {
public static void main(String[] args) {
System.out.println(Sex.男);
System.out.println(Sex.女汉子);
}
}
---------- Java ----------
男 为什么输出的是男 女汉子,枚举拓展在说明
女汉子
输出完成 (耗时 0 秒) - 正常终止
- 分析: 其实上面的写法是不推荐的(其中的对象字段不应该使用中文),应该这样写:【常见的写法】
enum Sex{
MAN,WOMAN
}
- 拓展: (希望打印上面的对象的时候打印出来是中文)
- 在每一个枚举对象中内置一个String类型的字段保存中文描述;
- 在创建每一个枚举对象的时候给中文描述字段赋值
- 覆写toString,返回当前枚举对象的中文描述
enum Sex{
MAN("男"),WOMAN("纯爷们");
String name;//为了跟枚举常量添加中文描述
Sex(String name){//声明构造方法初始化枚举常量的值
this.name = name;
}
@Override
public String toString(){
return this.name;
}
}
4.6 枚举拓展自Object
- 枚举拓展至Enum类,但是继承关系不能显示的写出来
- 枚举里面toString方法 从哪里来?从Object类来,那枚举和Object有关系吗?
- Enum类是Object的子类
java.lang.Object
java.lang.Enum<E>
这是所有 Java 语言枚举类型的公共基本类。
- 抽象(掌握)
- 什么是抽象:分类两大块抽象类,抽象方法,
- abstract修饰的类就是抽象类
- abstract修饰的方法就是抽象方法
5.2抽象类
- 抽象类是一个跟类一样的结构,抽象类本质也是一个类
- 类中有的成员,抽象类都可以有(字段 方法 构造方法),此外抽象类中还可以有抽象方法
abstract class Graph{
int i = 10;//抽象类中定义字段
public void add(){//抽象类中定义普通方法
}
Graph(){//抽象类中定义构造方法
}
}
- 抽象类不能够实例化
//测试类
class Test {
public static void main(String[] args) {
new Graph();
}
}
Test.java:4: 错误: Graph是抽象的; 无法实例化
new Griph();
^
1 个错误
输出完成 (耗时 0 秒) - 正常终止
- 抽象类的使用场景: 一般作为父类(基类,模板类),模板方法模式
- 支持多多态写法
5.3抽象方法
- 使用abstract 修饰的方法就是抽象方法没有方法主体;
- 抽象方法必须存于抽象类中[接口也可以],不能够放在普通类中
- 抽象类的子类
- 非抽象类必须覆写父类中的所有的抽象方法,
- 抽象类不用覆写父类中的抽象方法
5.4 抽象应用示例[会写]
class Test{
public static void main(String[] args) {
Graph g1 = new Circle();
}
Graph getP(){
return new Circle();//多态返回值形式,方法返回的是抽象类类型:所以方法内部,必然返回的是抽象类的子类对象
}
}
abstract class Graph{
abstract int getLength();//
}
class Circle extends Graph{
double r;//半径
int getLength(){
return 0;
}
}
5.5小结
- 为什么需要抽象:因为提取的公共的模板方法,根本没必要做任何实现,并且应该提示继承的类必须覆写
- 什么是抽象:
- abstract 修饰的类及方法 : 不创建对象
- 抽象类:abstract 修饰的一个类就是抽象类,字段普通方法,构造方法,都可以有,但是可以有抽象方法
- 抽象方法:abstract
- 修饰的一个方法就是抽象方法,只能存在于抽象类及接口中 没有方法体,
- 子类非抽象类,必须覆写抽象方法
- 抽象的作用: 模板类,基类,根类:主要作为公共的模板,提取公共的属性放到里面,让其他的子类继承,自己不能创建对象
- 接口(掌握)
6.1 接口的引入
- 同学们有没有听说过接口
接口以前已经提到过,比如 引用类型 包括 类 接口 数组 枚举,或者抽象方法可以存在抽象类或者接口里面;
提到接口 ,会想到啥?
- 现实生活中 USB接口
-
- 插入充电宝:在充电宝端实现了充电功能
- 插入手机:在手机端实现了数据传入,及充电功能
- 插入键盘:在键盘端实现了键盘输入
- 插入鼠标:在鼠标端实现了鼠标功能
- USB接口的体会:插入不同的设备实现不同的功能
6.2程序(软件开发)中的接口
- 对于接口有两种理解
- 软件与软件之间数据交互的接口【面试一般问的这个接口】
- java中的接口
- Java中的接口:是一个跟类很相似的结构
- 接口的语法:
interface 接口名{
}
- 接口一般写在一个独立的Java文件中,编译完毕之后也会生成独立的字节码文件
- 接口内部成员参考类
- 可以有字段:默认public static final 修饰的全局常量
- 方法全部都是抽象方法【没有 static final修饰 因为修饰的不能覆写,抽象方法需要覆写才有意义 】
- 构造方法没有
interface USB{
int i = 10;//默认public static final 修饰
void add();//默认public abstract 修饰
}
6.3接口如何使用
- 从结构上来看,接口中有全局常量和抽象方法
- 全局常量 : 接口名.常量名 直接调用
- 抽象方法 : 类实现接口,覆写接口中的抽象方法
- 子接口继承父接口,拓展接口
- 接口也是支持多态的写法的
6.4类实现接口
- 定义一个类来实现(implements)接口语法
interface A{}
class B implements A{
1) B非抽象类,必须全部覆写接口中的抽象方法
}
- A接口类型相当于是B类型的父类:支持多态写法
A a1 = new B(); // 多态的写法
a1.eat(); // 多态方法调用
- 一个类其实可以实现多个接口,需要覆写所有接口中的抽象方法
- 一个类可以在继承一个类的同时实现多个接口,但是继承的代码必须写实现前面
6.5接口-接口 拓展(extends 继承)
- 接口与接口之间支持允许继承
- 一个接口可以继承多个接口