第一章 Java概述


常用DOS命令

image.png

计算机语言的发展迭代史


第一代:机器语言 010101
第二代:汇编语言(不用再学了,太老了)
第三代:高级语言

面向过程的语言:c pascal fortran
面向对象的语言:java js python scala..

Java语言版本迭代概述


96年1.0发布
04年1.5/5.0发布
05年有一个更名
14年8.0版本

Java语言的特点

(1)面向对象
两个要素(类 对象) 三个特征(多态 封装 继承)
(2)健壮性
① 去除c语言中的指针
② 自动的垃圾回收机制 —-> 仍会出现内存溢出、内存泄漏(保姆跟不上你折腾的速度)
(3)跨平台性:write once ,run anywhere
JVM有着关键作用
教程用HotSpot,打开JAVA用 java -version命令可以查看版本

总结第一个程序:hello world

(1)java程序 编写-编译-运行 的过程
编写:我们将编写的JAVA代码保存在以“.java”结尾的源文件中
编译:使用javac.exe命令编译我们的java源文件,格式javac 源文件名.java
运行:使用java.exe命令解释运行我们的字节码文件。格式: java类名

(2)一个java源文件中可以声明多个class(即多个类),但是只能最多有一个类声明为public
pubilc可以修饰一个类,表示其权限大小。
也不能乱加,一般加的class名与文件名相同,否则运行时报错 ..是公共的
要求申明为public的类的类名与源文件名相同(这个逻辑应该在最多申明一个类之前,必须相同,所以只能有一个)

(3)程序的入口是main()方法,格式是固定的
除了args (arguments:参数)可以改变,
或者string后的 [] 放到参数后面也可以.
习惯上还是别改了

(4)输出语句:
System.out.println():先输出后换行
System.out.print():只输出数据
两个的区别是一个换行,一个不换行
即print输出后,在ln命令下换行,即 先输出,后换行

(5)执行语句末尾都以分号 ; 结束。从右往左看要么是 ; 要么是 }
关于{}的写法按老师的来即可,即 行尾风格

(6)编译的过程:
编译以后,会生成一个或者多个字节码文件,字节码文件的文件名和java源文件中的类名相同。
设了几个类,就有几个字节码文件
但是只能运行写了main方法的文件.

Java API 文档:

API: application programming interface:习惯上,把语言提供的类库,都称作api.
API文档:针对提供的类库如何使用给的一个说明书,类似于《新华字典》

良好的编程风格

image.png

第二章 基本语法

关键字与标识符

java关键字的使用

定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词)
特点:关键字中所字母都为小写

具体哪些关键字:

image.png
image.png

保留字

Java保留字:现有Java版本尚未使用,但以后版本可能会作为关键字使 用。
具体哪些保留字:goto 、const
注意:自己命名标识符时要避免使用这些保留字

标识符的使用

定义:Java 对各种变量、方法和类等要素命名时使用的字符序列称为标识符。凡是自己可以起名字的地方都叫标识符。
涉及到的结构:类名 变量名 方法名 多用。

规则:(必须要遵守。否则,编译不通过)
image.png

规范:(可以不遵守,不影响编译和运行。但是要求大家遵守)

image.png

注意点: 在起名字时,为了提高阅读性,要尽量意义,“见名知意”。

变量的使用

变量的分类


1.1 按数据类型分类(掌握)

image.png

详细说明:
1.整型:byte(1字节 8bit)(-128~127) short(2字节) int(4字节) long(8字节)

① byte表示范围为-128~127
② 声明long型变量,必须以“l”或者“L”结尾(其实不加l也可以,只是一个声明,不过会默认当成int类型)
③ 通常,定义整型变量时,使用Int型
④ 整型常量,默认是int

2.浮点型:float double

① 浮点型表示有小数点的数值
② float表示数值的范围比long还大
③ 定义float变量时,类似long,需要以f或者F结尾,默认是double,声明后才是float
③ 通常,定义浮点变量时,使用double型
⑤ 浮点常量,默认是double

3.字符型:char (1个字符=2个字=2byte=16bit节)

① 声明char型变量通常使用一对单引号(注意不是双引号)(有时也可以不用单引号)
例外:
因此,按这个逻辑,如果char中输入a,用 int 输出则为97
② 只能有一个字符,’AB’这种是编译不出来的,即只能声明一个字符,那种情况需要用-字符串-!
③ 表示方式:
1.声明一个字符;
2.转义字符
3.直接使用 Unicode 值来表示字符型常量(基本用1 2 ,3基本不用)
image.png

4.布尔型: boolean
只能取两个值:true、false
常常在 条件判断、循环结构中使用

两个重要小技巧:!!!!!!!!!!!!!!!!!!!(!!!!!!!!!)
1. 如果输出的语句中想输出””,每个”前应有\,即打成” “即可输出双引号和里面的内容;
2.如果想输出\n这种咋办?加一个\即可, 即输入\n时,会输出\n

1.2 按声明的位置分类(了解)

image.png

定义变量的格式

image.png

变量使用的注意点


(1)变量必须先声明,后使用;
使用前必须定义,若只定义未复制也会报错——编译错误
(2)变量都应该定义在作用域内,在此域内是有效的。换句话说,出了作用域就失效了。
作用域指的是所在的那个{}
(3)同一个作用域内不可以声明2个同名的变量

基本数据类型变量间运算规则


4.1 涉及到的基本数据类型:除了布尔类型外的7种


4.2 自动类型转换(只涉及7种基本数据类型)


(1) byte —> short—> int—> long (尽管占8个字节,表示的最大数也没有float大) —> float —> double
当容量小的数据类型的变量和容量大的数据类型的变量做运算时,就会自动提升为容量大的类型
(2)特别的:
当加入 char 后,变为
byte、short、char—> int—> long—> float —>double
即byte short char互相做运算(也包括自己和自己的运算)最后结果都只能用int类型表示,具体验证见后边的编码;
(少有资料说明,先作为结论吧,一般感觉还是这三个计算容易溢出,所以强行规定必须变成int)

说明:容量大小表示能表达的数的范围和大小,而不是所占内存的大小

4.3 强制类型转换(只涉及7种基本数据类型)


强制类型转换:自动类型提升运算的逆运算
1.需要使用强转符:()
2.注意点:强制类型转换可能导致精度损失。

4.4 String与8种基本数据类型间的运算(13章java常用类还会再说)


String类型变量的使用
1. String属于引用数据类型,不是基本数据类型;——翻译为:字符串
2. 声明String类型变量时,使用一对“”
3. String可以和8钟基本数据类型变量做运算(包括布尔型),且运算只能是连接运算,只能用加号 +;
4. 运算结果仍然是String类型

避免:
String s = 123; //编译错误
String s1 = “123”;
int i = (int)si;//编译错误
—> char的数字是可以用int输出的,但是String不行;char 和 int都是基本数据类型,String却是引用数据类型

运算符

流程控制

进制

第三章 数组

数组概述

一维数组

一维数组的声明与初始化

  1. int num;//声明
  2. num = 10;//初始化
  3. int id = 1001;//声明+初始化
  4. int[] ids;//声明——[]表示是数组,int表示数组元素的类型;
  5. //1.1 .静态初始化:数组的初始化(即new和数组元素的赋值操作同时***进行;
  6. ids = new int[]{1001,1002,1003,1004};
  7. //1.2 .动态初始化:数组的初始化和数组元素的赋值操作分开***进行;
  8. String[] names = new String[5];//5是指定长度的意思
  9. //即,还不知道数组元素是什么,先给造出来一个“壳”,内容等后期填入(如待填写银行账户)
  1. int[] arr1 = new int[]; ——>既没赋值,也没指定长度
  2. int[5] arr2 = new int[5]; ——>长度写错地方了
  3. int[] arr3 = new int[3]{1,2,3}; ——>长度指定了,值也附上了
  1. <br /> <br /> 总结:数组一旦初始化完成,其长度就确定了。不确定内存无法指定空间。

一维数组元素的引用

  1. names[0] = "李登0";//***java中数组角标(索引从0开始,到数组的长度-1结束。
  2. names[1] = "李登1";
  3. names[2] = "李登2";
  4. names[3] = "李登3";
  5. names[4] = "李登4";//字符串由多个字符构成,索引用charAt(),也是从0开始,这里得到“王”;
  6. //java中索引基本都是如此,从0开始;但仍有例外(和数据库交互的从1开始,如数据库中的表)
  7. //names[5] = "李登5"; ——>超出范围的编译不会报错,运行的时候才报错
  8. //因为编译只是生成字节码文件,没加载内存,这个错误只在加载内存即运行的时候才会报错

数组的属性

  1. //属性:length
  2. System.out.println(names.length);
  3. System.out.println(ids.length);

说明:数组一旦初始化,其长度就确定了。arr.length
数组长度一旦确定,就不可修改

一维数组的遍历

  1. for (int i = 0; i < names.length; i++){
  2. System.out.println(names[i]);
  3. }

一维数组元素的默认初始化值

数组元素是整型,默认初始化值都是 —> 0
数组元素是浮点型,默认初始化值都是 —> 0.0
数组元素是char型,默认初始化值都是 —> 0 或 ‘\u0000’,
(不是数值0,数值0对应编码48)
(这里的0对应阿斯卡的编码0,该编码对应“\0”,代表‘空格’的效果,但也不是真正的空格)
数组元素是boolean型,默认初始化值都是—> false
数组元素是引用数据类型时,默认初始化值都是—> null (这里指空值,而不是“null”)
(引用类型还没有展开讲,先以string为参考)

一维数组的内存结构(课件中有一些图,研究一下即可)

image.png

二维数组

数组常见算法

Arrays工具类的使用

1.理解
(1)定义在java.util的包下,使用前输入import java.util.Arrays;
(2)Arrays提供了很多操作数组的方法

2.使用

  1. //1.boolean equals(int[] a,int[] b):判断两个数组是否相等。
  2. //该类型为布尔型(先看是不是一个地址,然后长度数值都得一样)
  3. int[] arr1 = new int[]{1,2,3,4};
  4. int[] arr2 = new int[]{1,3,2,4};
  5. boolean isEquals = Arrays.equals(arr1, arr2);//ctrl点击查看源码
  6. System.out.println(isEquals);
  7. //2.String toString(int[] a):输出数组信息。-->相当于遍历,输出所元素
  8. System.out.println(Arrays.toString(arr1));
  9. //3.void fill(int[] a,int val):将指定值填充到数组之中。这个方法把所元素改为输入的这个变量
  10. Arrays.fill(arr1,10);//-->这样就把arr1中所结果赋值成为10;
  11. System.out.println(Arrays.toString(arr1));
  12. //输出结果为[10, 10, 10, 10],原来为[1, 2, 3, 4]
  13. //4.void sort(int[] a):对数组进行排序。底层用的快排
  14. Arrays.sort(arr2);
  15. System.out.println(Arrays.toString(arr2));
  16. //5.int binarySearch(int[] a,int key)--->这个是二分查找,其前提是序
  17. int[] arr3 = new int[]{-98,-34,2,34,54,66,79,105,210,333};
  18. int index = Arrays.binarySearch(arr3, 210);//左边是要查询的数组,右边是要查找的目标值
  19. if(index >= 0){//该方法未找到目标时,返回值为一个负数:由源码知,返回 -(low+1,与长度关
  20. System.out.println(index);
  21. }else{
  22. System.out.println("未找到");
  23. }

数组中常见异常

类与对象

面向对象学习的三条主线

Java类及类的成员:属性、方法、构造器;代码块、内部类
面向对象的大特征:封装性、继承性、多态性、(抽象性)
其它关键字:this、super、static、final、abstract、interface、package、import等

“大处着眼,小处着手”

面向对象与面向过程(理解)

举例对比:“人把大象装进冰箱”
1.面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
2.面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。

完成一个项目(或功能)的思路

image.png

面向对象中两个重要的概念

类:对一类事物的描述,是抽象的、概念上的定义。
对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)。
>面向对象程序设计的重点是类的设计。
>设计类,就是设计类的成员。

二者的关系:
【对象】是由【类】new出来的,派生出来的。

面向对象思想落地实现的规则一

1.创建类,设计类的成员
2.创建类的对象
3.通过“对象.属性”或“对象.方法”调用对象的结构

补充:几个概念的使用说明
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数 = method
创建类的对象 = 类的实例化 = 实例化类

对象的创建与对象的内存解析

典型代码:
Person p1 = new Person();
Person p2 = new Person();
Personp3 = p1;//没有新创建对象,共用了一个堆空间中的对象实体
说明:
如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的
意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。

匿名对象(day08没讲,day09的新知识)

特点:我们创建的对象,没显式的赋给一个变量名。即为匿名对象

  1. // new Phone().sendEmail();---->>>>>不用对象名字了,new完直接用
  2. // new Phone().playGame();
  3. //提出疑问:那上面这两个是一个对象吗?----不是,每new一次就是一个新的对象,看下边:
  4. new Phone().price = 1999;
  5. new Phone().showPrice();//0.0 ----不是同一个对象,赋值没啥用

应用场景:新参是自定义类型时,就不用自己去命名一个了,直接用匿名对象赋给一个有名的对象,便可以多次使用

  1. PhoneMall mall = new PhoneMall();
  2. // mall.show(p);
  3. // 匿名对象的使用
  4. mall.show(new Phone());//即这里不用再造个对象起个名,如p,这里直接用匿名对象调用
  5. //其中
  6. class PhoneMall{
  7. public void show(Phone phone){//方法中形参可以是任意类型。所以也可以是phone类型,对应75行类型
  8. phone.sendEmail();
  9. phone.playGame();
  10. }
  11. }

理解”万事万物皆对象”

(1)在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构
>Scanner,String等
>文件:File
>网络资源:URL
(2)涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。

第四章 面向对象:三大特性

封装性

为什么要引入封装性?

我们程序设计追求“高内聚,低耦合”。

高内聚 :类的内部数据操作细节自己完成,不允许外部干涉; (即私有化)
低耦合 :仅对外暴露少量的方法用于使用。 (权限变大)

隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提 高系统的可扩展性、可维护性。
通俗的说,把该隐藏的隐藏起来,该暴露 的暴露出来。这就是封装性的设计思想。

问题引入: 属性的私有化

当我们创建一个类的对象以后,我们可以通过 “对象.属性” 的方式,对对象的属性进行赋值。
这里,赋值操作属性的数据类型和存储范围的制约。除此之外,没其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs()同时,我们需要避免用户再使用”对象.属性”的方式对属性进行赋值。则需要将属性声明为私有的(private).
—>此时,针对于属性就体现了封装性。

注意,这里是体现了封装性,而不是等同于封装性

封装性思想具体的代码体现:

封装性的体现(≠封装性—-封装后还能使用,提供get和set功能【①赋值/设置 ②调用/设置】:
我们将类的属性xxx私化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值 ==> 最终目的是不允许用户跳过方法直接调用属性;

拓展(这里的私化只是封装性的体现的一部分,其实还有其他类型):
封装性的体现:① 如上 ;
② 不对外暴露的私的方法,即自己类内部可以调用,不能再其他类调用;
③ 单例模式(讲了构造器和static关键字后会提到构造器私化 …

不能单纯的认为private体现封装性,其实public也是封装性的体现,不能太狭隘

体现一:类的属性xxx私化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值

  1. private double radius;
  2. public void setRadius(double radius){
  3. this.radius = radius;
  4. }
  5. public double getRadius(){
  6. return radius;
  7. }
  8. public double findArea(){
  9. return 3.14 * getRadius() * radius;
  10. }

体现二:不对外暴露的私有的方法,即自己类内部可以调用,不能再其他类调用;
体现三:单例模式(讲了构造器和static关键字后会提到构造器私化
-外部不能随便调用构造器,只能内部造单独的一个实例对象)
体现四:如果不希望类在包外被调用,可以把类声明为缺省的。

Java规定的四种权限修饰符

4.1 权限从小到大顺序为:

image.png

4.2 具体的修饰范围:

image.png

4.3 权限修饰符可用来修饰的结构说明:

封装性的体现,需要权限修饰符来配合。
1. Java规定的4种权限(从小到大排列:private、缺省、protected 、public 。
2. 4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类(代码块不行。
3. 具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类。
修饰类的话,只能使用:缺省、public。

总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。

继承性

继承应用:方法的重写

什么是方法的重写(override 或 overwrite)?

子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作

应用

重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。
当然,你子类里面重写了,调用父类的同名方法,那还是父类以前的不是现在重写的方法.
(重写后,左侧行数处会一个小绿色三角形提示,此为重写方法)

举例

  1. class Circle{
  2. public double findArea(){}//求面积
  3. }
  4. class Cylinder extends Circle{
  5. public double findArea(){}//求表面积
  6. }

重写的规则:(记一下)

约定俗称:子类中的叫【重写】的方法,父类中的叫【被重写】的方法

  1. 方法的声明: 权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
  2. //方法体(这块肯定是不同的
  3. }


① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
(这一点同重载,用来确定是哪个方法)
② 子类重写的方法的权限修饰符【不小于】父类被重写的方法的权限修饰符
>理解方式:摊煎饼果子,要想覆盖掉原来的煎饼果子,你新的煎饼果子就要比原来的大才行
>特殊情况:子类不能重写父类中声明为private权限的方法;
若重写格式操作了,也不报错,权当写了一个新方法;因为权限太小,子类看不到,无所谓覆盖了
③ 返回值类型:
>父类被重写的方法的返回值类型是[void],则子类重写的方法的返回值类型[只能是void]
>父类被重写的方法的返回值类型是[A类型(这里指的是引用数据类型中的类],
则子类重写的方法的返回值类型可以是[A类或A类的子类]。
例如父类中方法返回object类,子类返回String也是没问题的
>父类被重写的方法的返回值类型是[基本数据类型(比如:double)],
则子类重写的方法的返回值类型[必须是相同的基本数据类型(必须也是double)]
其实这一点就是第二条中的A类对A类,因为基本数据类型不存在子类,【自动类型提升不是子父类关系】

④ 子类重写的方法抛出的异常类型[不大于]父类被重写的方法抛出的异常类型(具体放到异常处理时候讲

>返回值类型,异常类型的子父类中的【大小关系】与权限中的大小关系相反

>实际开发中其实不用记上面这些条条框框,一般来说,直接把父类部分除方法体的内容粘过来就行,
权限和返回值啥的不用改,就改方法体,这样一定不会错。
或者你把方法名写上,直接alt+/弹出提示部分,会重写的项

**(以下额外关注
子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写,要么都声明为static的(不是重写。
static写在权限修饰符后面;
静态方法不能被覆盖,随着类的加载而加载

经典面试题:区分方法的重载与重写(除了这里讲的,多态性中也却别

面试题:区分方法的重写和重载?

答:
(1)二者的概念;
(2)重载和重写的规则;
(3)重载不认多态;重写表现为多态

重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不 同的参数表,对同名方法的名称做修饰。
对于编译器而言,这些同名方法就成了 不同的方法。它们的调用地址在编译期就绑定了。
Java的重载是可以包括父类 和子类的,即子类可以重载父类的同名不同参数的方法。
所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法, 这称为“早绑定”或“静态绑定”;
而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体 方法,这称为“晚绑定”或“动态绑定”。
引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。

多态性

多态性的理解

可以理解为一个事物的多种形态。

何为多态性

父类的引用指向子类的对象(或子类的对象赋给父类的引用)

举例:
Person p = new Man();
Object obj = new Date();

多态性的使用:虚拟方法调用

了对象的多态性以后,我们在编译期,只能调用父类中声明的方法;
但在运行期,我们实际执行的是子类重写父类的方法。
(ctrl+左键 发现进入父类,而不是运行结果代表得子类)

总结:编译,看左边;运行,看右边。

多态性的使用前提

  1. 类的继承关系,得父类子类 .<br /> 方法的重写 .

多态性的应用举例

(AnimalTest类中去找)
举例1:

  1. public void func(Animal animal){//Animal animal = new Dog();
  2. animal.eat();
  3. animal.shout();
  4. }

举例2:

  1. class Order{
  2. public void method(Object obj){
  3. //由语句 equals(Object obj);这种,没多态性就太难应用了
  4. }
  5. }

举例3:

  1. class Driver{
  2. public void doData(Connection conn){//conn = new MySQlConnection(); / conn = new OracleConnection();
  3. //规范的步骤去操作数据
  4. // conn.method1();
  5. // conn.method2();
  6. // conn.method3();
  7. }
  8. }

多态性使用的注意点

对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边的类型(属性也不存在重写一说)

  1. ==> 关于属性,在前面关于super的介绍中,提到了同名的方法和同名的属性的调用;<br />同名的方法会被覆盖;同名的属性不会被覆盖,父类的同名属性会存在于栈空间,但是会调用子类的;<br /> 而在多态性这里,属性的位置由命名时左侧类型决定

关于向上转型(1-6均为向上转型)与向下转型(父类到子类)

//具体见day13.com.atguigu.java.PersonTest

7.1 向上转型

多态——父类定个大概,子类据此详细展开

7.2 向下转型

父类引用转成子类的声明——子类有但父类没有的方法也需要执行

7.2.1 为什么使用向下转型

==> 有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特的属性和方法不能调用。

==> 用内存理解的时候应该明白,类类型存储的地址值前半部分代表的是类型,父类类型执行不了子类类型 特的,但是转换类型以后就可以了,

7.2.2 如何实现向下转型

==>那么就应该转换它的类型,父类变成子类,类似之前自动类型提升中的强制转型
向下转型:使用强制类型转换符。(多态其实可以认为是向上转型
Man m1 = (Man)p2;//(p2原来类型是Man的子类)

7.2.3 使用时的注意点

==>使用强转时,可能出现ClassCastException的异常,即类型转换异常;
(均作为Person子类的Man和Woman,因为已经转成man了,虽然编译可以,运行时候man->waman时就问题)

==>为此,可以先通过instanceof进行判断,返回true就向下转型。返回false不进行向下转型

7.2.4 instanceof 的使用

instanceof关键字的使用:为了避免上述异常的情况,这个关键字应运而生
1.使用:a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
(注意instanceof两边不是平等的,左边是实例,右边是类)
其实,操作的时候,a所属的类必须与A类是子类或者父类的关系,否则编译都过不了

  1. 2.使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先<br /> 进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。

3.如果 a instanceof A返回true,则 a instanceof B也返回true.
其中,类B是类A的父类。

7.2.5 图示

image.png

面试题

8.1 谈谈你对多态性的理解?
① 实现代码的通用性。
② Object类中定义的public boolean equals(Object obj){ }
JDBC:使用java程序操作(获取数据库连接、CRUD)数据库(MySQL、Oracle、DB2、SQL Server)
③ 抽象类、接口的使用肯定体现了多态性。(抽象类、接口不能实例化)

8.2 多态是 编译时行为 还是 运行时行为?
运行时行为
课后有证明:随机数的那个

多态应用:包装类的使用

1.为什么要有包装类(或封装类)
为了使得基本数据类型的变量具有类的特征,引入包装类
2.基本数据类型与对应的包装类:

3.需要掌握的类型间的转换:(基本数据类型、包装类、String)
(1)

(2)简易版:
基本数据类型<—->包装类:自动拆装箱
基本数据类型、包装类—->String:调用String重载的valueOf(Xxx xxx)
String<—-基本数据类型、包装类:调用包装类的parseXxx(String s)方法
注意:转换时,可能会报NumberFormatException
(3)应用场景举例:
① Vector类中关于添加元素,只定义了形参为Object类型的方法
v.addElement(Object obj); //基本数据类型—>包装类—>使用多态

第五章 面向对象:关键字

this

package / import

super

static

static:静态的

可以用来修饰的结构:主要针对内部结构

属性、方法、代码块、内部类;类,构造器不行
==>类的内部结构要么随着类的加载而加载,即静态的;要么随着对象加载而加载,即非static的;
构造器处在这两种情况中间,所以别搞它了,类变到对象的过程便是new+构造器。

static修饰属性:

静态变量(或类变量
3.1 属性,是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
==>实例变量:我们创建了类的多个对象,每个对象都独立的拥一套类中的非静态属性。当修改其中一个对象中的
非静态属性时,不会导致其他对象中同样的属性值的修改。
==>静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致
其他对象调用此静态变量时,是修改过了的。
3.2 static修饰属性的其他说明:
① 静态变量随着类的加载而加载。可以通过”类.静态变量”的方式进行调用
(类的加载早于对象,所以静态变量的加载早于对象
② 静态变量的加载要早于对象的创建。
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在【方法区的静态域】中。

(小结(能调用就是yes
④ 类变量 实例变量
类 yes no
对象 yes yes

3.3 静态属性举例:System.out; Math.PI;这里都没建立对象,直接用类调用了

静态变量内存解析

image.png

static修饰方法

使用static修饰方法:静态方法——无需对象,可直接由类调用

  1. 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用<br /> 静态方法 非静态方法<br /> yes no<br /> 对象 yes yes<br /> 不同于属性的一点:静态方法中能调用非静态变量吗?<br /> ==> 静态方法中,只能调用静态的方法或属性<br /> ==> 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性<br /> <br /> (静态的比非静态的早出现,所以调不了晚出现的非静态;你可以向你爸借钱,但是你不能向你没出生的儿子借钱

static的注意点

5.1 在静态的方法内,不能使用this关键字、super关键字。因为静态的不属于对象,this和super基于对象使用
5.2 关于静态属性和静态方法的使用,大家都从【生命周期】的角度去理解。(??????)

如何判定属性和方法应该使用static关键字:

6.1 关于属性
> 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
> 类中的常量也常常声明为static(比如Math.PI,其中还加了一个final
6.2 关于方法
> 操作静态属性的方法,通常设置为static的
> 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections

使用举例:

==>注意:final作用时,不代表每个对象中修饰的值相同,只是赋值后不可以再改了(联想每个人与身份证号码的关系)
举例1:Arrays\Math\Collections工具类等(调出源码:ctrl+点击/ctrl+shift+t)
举例2:单例模式
举例3:

  1. class Circle{
  2. private double radius;
  3. private int id;//自动赋值
  4. public Circle(){//注意这个方法的内容,每new一个对象,会自动累加
  5. id = init++;
  6. total++;
  7. }
  8. public Circle(double radius){
  9. this();//不同的构造器中都要体现出自动赋值
  10. // id = init++;
  11. // total++;
  12. this.radius = radius;
  13. }
  14. private static int total;//记录创建的圆的个数
  15. private static int init = 1001;//static声明的属性被所对象所共享
  16. public double findArea(){
  17. return 3.14 * radius * radius;
  18. }
  19. public double getRadius() {
  20. return radius;
  21. }
  22. public void setRadius(double radius) {
  23. this.radius = radius;
  24. }
  25. public int getId() {
  26. return id;
  27. }
  28. public static int getTotal() {
  29. //属性是static,操作的方法一般也是static
  30. //这里因为total已经在构造器中自动累加了,所以没设置get方法
  31. return total;
  32. }
  33. }

final

final:最终的
1.可以用来修饰:类、方法、变量

2.具体的:

  • —> final 用来修饰一个类:此类不能被其他类所继承。(太监类,不能子类继承
    比如:String类、System类、StringBuffer类

    —> final 用来修饰方法:表明此方法不可以被重写(此方法不需要扩充了)
    比如:Object类中getClass();

    —> final 用来修饰变量:此时的”变量”就称为是一个常量(不准变来变去了/注意,这里没说属性,属性只是变量中的一种)
    .1 final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化
    (默认和方法中不行;构造器加载的时候属性就得值了,方法起一个修改作用)
    (之前提到了5类初始化的方法

    .2 final修饰局部变量:
    尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值
    以后,就只能在方法体内使用此形参,但不能进行重新赋值。

  • ==> static final 用来修饰属性:全局常量
    static能修饰属性、方法、代码块、内部类(构造器不行
    final能修饰属性、方法和类
    两者能共同修饰的属性和方法
    一般方法是不定义final的,这两个组合在修饰属性中用的多

    abstract

    abstract: 抽象的
    1.可以用来修饰:类、方法
    2.具体的:
    abstract修饰类:抽象类
    > 此类不能实例化
    > 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
    * > 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作 —->抽象的使用前提:继承性

abstract修饰方法:抽象方法
> 抽象方法只方法的声明,没方法体
> 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
> 若子类重写了父类中的所的抽象方法后,此子类方可实例化
若子类没重写父类中的所的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
3.注意点:
1.abstract不能用来修饰:属性、构造器等结构
2.abstract不能用来修饰私方法、静态方法、final的方法、final的类

4.abstract的应用举例:
举例一:

举例二:

  1. abstract class GeometricObject{
  2. public abstract double findArea();
  3. }
  4. class Circle extends GeometricObject{
  5. private double radius;
  6. public double findArea(){
  7. return 3.14 * radius * radius;
  8. };
  9. }

举例三:IO流中设计到的抽象类:InputStream/OutputStream / Reader /Writer。在其内部
定义了抽象的read()、write()方法。

interface

第六章 面向对象:类的结构

属性

方法

构造器

代码块

内部类

面试题

请你说说==与equals()的区别

解题思路
得分点 ==和equals()比较基本变量用法,==和equals()对比引用变量的用法 标准回答 ==和EQUALS都是JAVA中判断两个变量是否相等的方式,如果判断的是两个基本类型的变量,并且两者都是数值类型(不一定要求数据类型完全相同),只要两个变量的值相等就会返回TRUE。对于两个引用变量只有他们指向同一个引用时,==才会返回TRUE。==不能用于比较类型上没有父子关系的两个对象。 EQUALS()方法是OBJECT类提供的一个实例方法,所以所有的引用变量都能调用EQUALS()方法来判断他是否与其他引用变量相等,但使用这个方法来判断两个引用对象是否相等的判断标准与使用==运算符没有区别,它同样要求两个引用变量指向同一个对象才会返回TRUE,但如果这样的话EQUALS()方法就没有了存在的意义,所以如果我们希望自定义判断相等的标准时,可以通过重写EQUALS方法来实现。重写EQUALS()方法时,相等条件是由业务要求决定的,因此EQUALS()方法的实现是由业务要求决定的。

说说static修饰符的用法

解题思路
得分点 static可以修饰什么,static的重要规则 标准答案 Java类中包含了成员变量、方法、构造器、初始化块和内部类(包括接口、枚举)5种成员,static关键字可以修饰除了构造器外的其他4种成员。static关键字修饰的成员被称为类成员。类成员属于整个类,不属于单个对象。 static关键字有一条非常重要的规则,即类成员不能访问实例成员,因为类成员属于类的,类成员的作用域比实例成员的作用域更大,很容易出现类成员初始化完成时,但实例成员还没被初始化,这时如果类成员访问实力成员就会引起大量错误。 加分回答 static修饰的部分会和类同时被加载。被static修饰的成员先于对象存在,因此,当一个类加载完毕,即使没有创建对象也可以去访问被static修饰的部分。 静态方法中没有this关键词,因为静态方法是和类同时被加载的,而this是随着对象的创建存在的。静态比对象优先存在。也就是说,静态可以访问静态,但静态不能访问非静态而非静态可以访问静态。

请你说说重载和重写的区别,构造方法能不能重写

解题思路
得分点 重载定义、重写定义 标准回答 重载要求发生在同一个类中,多个方法之间方法名相同且参数列表不同。注意重载与方法的返回值以及访问修饰符无关。 重写发生在父类子类中,若子类方法想要和父类方法构成重写关系,则它的方法名、参数列表必须与父类方法相同。另外,返回值要小于等于父类方法,抛出的异常要小于等于父类方法,访问修饰符则要大于等于父类方法。若父类方法的访问修饰符为private,则子类不能对其重写。 其实除了二者都发生在方法之间,要求方法名相同之外并没有太大相同点。 加分回答 同一个类中有多个构造器,多个构造器的形参列表不同就被称为构造器重载,构造器重载让Java类包含了多个初始化逻辑,从而允许使用不同的构造器来初始化对象。 构造方法不能重写。因为构造方法需要和类保持同名,而重写的要求是子类方法要和父类方法保持同名。如果允许重写构造方法的话,那么子类中将会存在与类名不同的构造方法,这与构造方法的要求是矛盾的。 父类方法和子类方法之间也有可能发生重载,因为子类会获得父类的方法,如果子类中定义了一个与父类方法名字相同但参数列表不同的方法,就会形成子类方法和父类方法的重载。

请你说一下final关键字

解题思路
得分点 final类,final方法,final变量 标准答案 final关键字可以用来标志其修饰的类,方法和变量不可变。 当final修饰类时,该类不能被继承,例如java.lang.Math类就是一个final类,它不能被继承。 final修饰的方法不能被重写,如果出于某些原因你不希望子类重写父类的某个方法,就可以用final关键字修饰这个方法。 当final用来修饰变量时,代表该变量不可被改变,一旦获得了初始值,该final变量的值就不能被重新赋值。 final既可以修饰成员变量(包括类变量和实例变量),也可以修饰局部变量、形参。 加分回答 对于final修饰的成员变量而言,一旦有了初始值就不能被重新赋值,如果既没有在定义成员变量时指定初始值,也没有在初始化块,构造器中为成员变量指定初始值,那么这个成员变量的值将一直是系统默认分配的0、’\u0000’、false或者是null,那么这个成员变量就失去了存在的意义,所以Java语法规定:final修饰的成员变量必须由程序员显示的指定初始值。 final修饰的实例变量,要么在定义该实例变量时指定初始值,要么在普通初始化块或构造器中为该实例变量指定初始值。但要注意的是,如果普通初始化块已经为某个实例变量指定了初始值,则不能再在构造器中为该实例变量指定初始值;final修饰的类变量,要么在定义该变量时指定初始值,要么在静态初始化块中为该类变量指定初始值。 实例变量不能在静态初始化块中指定初始值,因为静态初始化块是静态成员,不可以访问实例变量;类变量不能在普通初始化块中指定初始值,因为类变量在类初始化阶段已经被初始化了,普通的初始化块不能为其重新赋值。 系统不会为局部变量进行初始化,所以局部变量必须由程序员显示的初始化。因此使用final修饰局部变量时,既可以在定义时指定默认值,也可以不指定默认值。如果final修饰的局部变量在定义是没有指定默认值,则可以在后面的代码中对该final变量赋初始值,但只能一次,不能重复赋值;如果final修饰的局部变量在定义时已经指定默认值,则后面代码中不能再对该变量赋值。

请你说一下抽象类和接口的区别

解题思路
得分点 接口与抽象类的方法,接口与抽象类的常量与变量,单继承多实现 标准答案 接口和抽象类相同点有: - 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其它类实现和继承 - 接口和抽象类都可以有抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法 在用法上,接口和抽象类也有如下差异: - 接口里只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类则可以包含普通方法。 - 接口里只能定义静态常量,不能定义普通成员变量;抽象类里既可以定义普通成员变量,也可以定义静态常量 - 接口里不包含构造器;抽象类可以包含构造器,但抽象类的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作 - 接口里不能包含初始化块,抽象类则可以包含初始化块 - 一个类最多只能有一个父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足 总之,接口通常是定义允许多个实现的类型的最佳途径,但当演变的容易性比灵活性和功能更加重要时,应该使用抽象类来定义类型。 加分回答 在二者的设计目的上,接口作为系统与外界交互的窗口,体现了一种规范。对于接口的实现者来说,接口规定了实现者必须向外提供哪些服务;对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务。当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准。 抽象类则不一样,抽象类作为系统中多个子类的共同父类,它体现的是一种模板式设计。抽象类作为多个子类的父类,它可以被当作系统实现过程中的中间产品,这个中间产品已经实现了系统的部分功能,但这个产品依然不能当作最终产品,必须要有更进一步的完善。这种完善可能有几种不同方式。

END