Java入门快速通关笔记
双非大二冲 Java 后端实习|Java 基础入门笔记
作为一名双非大二软件工程专业的学生,现阶段正朝着 Java 后端实习的目标发力。回顾 Java 入门阶段的学习,从环境搭建到基础语法,再到流程控制,看似简单的知识点里藏着不少容易踩的坑。结合之前学习中遇到的疑问和踩过的雷,我将 Java 基础核心概念、流程控制关键要点 以及入门阶段的高频疑问,整理成这篇入门笔记。既作为自己的知识复盘,也希望能给和我一样的初学者提供一些参考。
一、开篇说明:入门笔记的定位
本篇笔记聚焦Java 入门核心模块,涵盖「Java 基础语法」「Java 方法」「Java 流程控制」三大板块。前期学习时节奏较快,由于并未一开始使用该博客记录Java的日常学习,对部分基础概念并未做出实时的总结的层面,缺乏系统梳理;从数组章节开始,我会进行精细化学习并实时记录。因此,本篇笔记主要对前期核心知识点进行重点提炼和误区总结,搭配简洁的代码示例和易懂的解析,帮自己夯实基础,为后续数组、面向对象等核心内容的学习铺路。
(同理,在数组之前的基础Java代码我在idea上有过大量的基层代码编写,但在这里为了学习进度的关系我就不附加代码解释了,但在数组之后的学习还有之前的重要代码我会做些许的整理)
二、Java 基础语法:入门必避的“基础坑”
Java 基础语法是构建所有程序的基石,看似简单的关键字、数据类型、输入输出,实则藏着很多初学者容易忽略的细节。结合之前的学习疑问,我将核心知识点和易错点以及目录整理如下:
/==============================================================
目录:
1.数据基础认知
2.流程控制使用
3.流程控制题+解
4.方法的运用
5.数组的运用
6.面向对象编程的思想
===============================================================
1.数据基础认知
1.1数据类型:别混淆基本类型与引用类型
这是入门阶段最容易模糊的概念,尤其是在后续学习方法传参时,这个知识点会直接影响对代码逻辑的理解。
1.2 基本数据类型(8种):直接存储数据值,占用固定内存空间,包括 byte 、 short 、 int 、 long 、 float 、 double 、 char 、 boolean 。
- 易错点: long 类型赋值时,必须在数字后加 L (如 long num = 10000000000L; ),否则会被默认当作 int 处理,导致数值溢出; float 类型同理,需加 F ,这是一些简单的代码规范,平时需要注意。
1.3引用数据类型:存储的是数据的内存地址,占用内存空间不固定,如字符串 String 、数组、类对象等。
- 易错点: String 是引用类型,而非基本类型,很多初学者会将其归为 8 种基本类型之一,这是核心误区。
- String在使用过程中需要注意首字母大小写的问题,这是第一步;然后还要对它的类型有了解,对于字符串的应用上多使用String,其实对于计算机底层的逻辑上讲,所有的字符(汉字等)都是另一种形式的编码代替,就像是在诺大的一本字典里寻找各自的代表文字等字符;
1.4自增自减运算符(新手容易踩坑)
- 第一是前置自增++a和后置自增a++的底层运行逻辑,这里要记清“先加后用”和“先用后加”的区别;第二是自增运算符在循环条件中的陷阱,比如for(int i=0;i<5;i++)和for(int i=0;i<5;++i)在单变量循环里效果一致,但在多变量嵌套循环里会有性能差异;第三是自增和赋值运算符的结合优先级问题,重点记住“赋值运算优先级低于自增运算”这个规则,避免a = b++这类表达式的计算错误。
1.5Java 包(package)与导入(import)核心笔记 包(package的作用:像“文件夹”一样,对类和接口进行分门别类,避免类名冲突,方便代码管理和维护。
- 多层包之间用英文句点 . 间隔。
- 命名形式通常为“公司域名倒序 + 项目名 + 模块名”,例如: com.amazon.data.entity (亚马逊数据实体包)。
- package 语句必须放在类文件的第一行,用来声明当前类属于哪个包。
- 示例: package com.example.demo; 导入(import)的作用:用来声明当前类中使用的其他类来自哪个包,让编译器能够找到并加载这些类。
- java.lang 包下的类(如 String 、 System 、 Math )是 Java 语言的核心类,JVM 会自动导入,因此使用时可以不写 import 语句。
- 语法示例:
- 导入单个类: import java.util.Scanner;
- 导入整个包: import java.util.*; (不推荐,会降低编译效率) 常见面试/实战拓展
- 静态导入(static import):可以直接导入类的静态方法和静态变量,使用时无需写类名。
- 示例: import static java.lang.Math.PI; 之后可直接写 PI 而非 Math.PI 。
- 包访问权限:如果一个类或成员没有访问修饰符(如 public 、 private ),则它具有“包访问权限”,即只能被同一个包内的其他类访问。
- 全类名使用:当两个不同包中有同名类时(如 java.util.Date 和 java.sql.Date ),必须使用全类名来区分,例如: java.util.Date now = new java.util.Date(); 。
2.流程控制使用
2.1 输入输出:Scanner 类的“换行符陷阱”
2.1.1 Scanner的输入代码格式为:Scanner sc = new Scanner(System.in);
<凡是io流的类如果不关闭将会一直占用资源,要养成好的代码习惯,用完就关闭>
sc.close();这就是调用位于Scanner类的一个close方法来达到释放资源的效果,前面的sc是创建出来的对象,调用对象的方法等同于调用大类的方法,这会在面向基础和方法中有所提及。
2.2在练习流程控制、算法题时, Scanner 类是最常用的输入工具,但它的 next() 和 nextLine() 方法极易混用出错,这也是我之前调试代码时遇到的高频问题,这两个方式属于Scanner类里面的两个方法,类其中还会有很多判断方法,提一嘴hasNextInt()和hasNextFloat(),他们都是判断条件,若下一个数位int或float类型就结束循环,通常是在if等判断或while等循环语句中的条件中出现。
以下代码是类似情况,对double类型的一个判断:
2.2.1 核心区别
- next() :只读取到空格为止,不会读取换行符,光标停留在当前行。
- nextLine() :读取整行内容,包括换行符,读取后光标移至下一行。 2.2.2 陷阱场景:当 next() 和 nextLine() 连续使用时, nextLine() 会读取到 next() 遗留的换行符,导致直接跳过输入。 解决方案:在 next() 后额外调用一次 nextLine() 吸收换行符
2.3 多种结构构建Java语法
【作者说:关于这个选择结构视频讲解内容比较简单,个人感觉也很好理解,代码上只用了三个简单代码实验,但是后面会有一个简单的小系统用到了if语句,switch语句,while循环还包括:方法调用,重载等手段,项目比较简单。纯手搓加上AI修正,后续会展现出来。当然这里的流程结构我会展现Switch选择结构和简单的for循环讲解,结构上也会有适当省略。】
主要内容及课题包括:顺序结构,if选择结构,Switch选择结构,while循环结构,dowhile循环结构,for循环结构以及break,continue等用法
2.3.1 Switch选择结构:
switch 语句常见陷阱
1. switch 只能判断:byte、short、int、char、String、枚举 不能判断 long、float、double、boolean,一用就报错。
2. case 后面必须是常量,不能是变量 例如 case a: 是错的,必须写固定值 case 1: 。
3. case 穿透问题(容易忘)
每个 case 结束必须写 break,否则会继续执行下面所有 case,这是最大漏洞。
4. default 可以写在任意位置,但建议放最后 如果 default 放前面又没 break,一样会穿透。
5. switch 不能写 > < >= <= 这种范围判断 switch 只能判断等值,不能判断区间,区间必须用 if。
6.基本语法:
case "c":
System.out.println("你学习的语言是c" );
break;
case "Python":
System.out.println("你学习的语言是Python" );
break;
case "go":
System.out.println("你学习的语言是go" );
break;
case "Java":
System.out.println("你学习的语言是Java");
break;
default:
System.out.println("Unknown");
System.exit(0);//若输出错误语言格式,这个用法将会在输出Unknown后结束,不会继续生成期末成绩
break;
<这是我做的关于编程语言与成绩分析的小系统上的代码内容,系统内运行基本完善,也有许多可以补充的内容,
但我打算后面学java可视化,javaweb和数据库系统原理的时候将这个系统做成网页版>
3.流程控制作业
【作者说:我在这里给了两道适合新手做的小题目,这两道题都运用了for循环plus版本,对新手理解for循环有极大的帮助,我在这里也深刻地认识并学习到for循环的基础嵌套。】
Problem 1:
P1.打印九九乘法表:
代码展示:
public static void main(String[] args) {
for (int i = 1; i <=9; i++) {
for (int x = 1; x <=i; x++) {
System.out.print(i + "*" + x + "=" + (x*i) + "\t" );
}
System.out.println();
}
}
运行结果展示:
Problem 2:
P2.打印三角形:(化简思想,大化小思想)
代码展示:
public static void main(String[] args) {
//打印三角形
for (int i = 1; i <= 5; i++) {
for (int j = 5; j >= i; j--) {
System.out.print(" ");
}
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
for (int j = 1; j < i; j++) {
System.out.print("*");
}
System.out.println();
}
}
运行结果展示:
【作者说;在两个代码里,主要练习代码思维,就拿打印三角形代码中的4到5行代码输入空格来讲,就是三角形左边按一部分的倒直角三角形,等于说是把梯形左边的一部分挖掉了,这个运行过程有点难理解,就可以使用计算机编译器的断点调试方法来加深理解。在这两个题目代码中也共同涉及换行的大难题,比如说P1中的4,6行与P2中的5,8,11,13行的print与输出空格的输出语句,这是一个值得探讨与学习的地方,建议在循环中多使用多理解多收获。】
3.1 换行问题小总结
//println 输出完会换行
//print 输出完不会换行
/t 相当于“tab键”让控制台空格
4.方法的运用
【作者说;方法这一方面写的就比较少,因为上面很多的代码大多都离不开方法的调用,比如代码程序的入口main方法就是一个非常常见且重要的方法,所以我主要说一下一些方法的调用格式和变量名(方法名)的规范,当然方法很多地方都会牵扯到面向对象基础,所以关于对象与方法之间的调用我也会在这里讲一小部分,在数组后面的面向对象章节我又会讲小部分。】
4.1 方法在类中的位置与归属
-
方法是类的重要组成部分,定义在类的内部、类方法之外(与成员变量同级)。
-
一个类可以包含多个方法,用于描述该类对象的行为或功能。
4.2 方法的调用方式
- 基于类创建对象(实例化)后,通过一定格式展现,代码展示;
类名 对象名 = new类名();
对象名.方法();
- 新创建的对象会自动拥有其所属类中定义的所有方法,可直接调用。->回顾2.1的内容中,Scanner中new出的新对象sc可以直接调用close(),Next()等方法。
4.3 方法的命名规范
-类成员/局部变量;首字母小写和驼峰原则 monthSalary(); -常量:大写字母和下划线 MAX_VALUE -类名:首字母大写和驼峰原则 Man,GoodMan -方法名:首字母小写和驼峰原则 run(),runRun()
4.4 方法与成员变量、局部变量的区分
- 成员变量(属性):定义在类内、方法外,属于类的属性,整个类内都可访问。
- 局部变量:定义在方法体内部,仅在该方法执行期间有效,方法执行结束后变量失效。
5.数组的运用
【作者说:数组这方面的运用大多体现在各种代码的基层原理上,主要讲的内容也比较少,我主要凸显数组的初始化方法,一些Java内存的分析,二维数组,冒泡排序和Java中Arrays类的讲解和使用】
5.1 Java的内存分析
Java内存=堆+栈+方法区:
·堆用来存放new的对象和数组,可以被所有线程共享,不会存放别的对象引用,是一大片空间
·栈用来存放基本变量类型和引用对象的变量,这里涉及到数据结构栈的知识比较多
·方法区可以被所有线程共享,包含所有的Class和Static变量
5.2 数组的初始化和代码展示(包含解析)
public class Arraysdemo1 {
//三种初始化方式
public static void main(String[] args) {
//静态初始化
int[] a = {0,1,2,3,4,5,6};//复制完毕后,空间不能改变
System.out.println(a[0]);
//动态初始化
int[] b = new int[10]; //创建完空间后,里面所有值默认为0,需要手动赋值
b[0] = 10;
System.out.println(b[0]);
/*数组的默认初始化(包含于动态初始化)
数组为引用类型,它的元素相当于类的实体变量,因此数组一分配空间,其中的每个
元素也按照实体变量同样的方式被隐式初始化*/
}
5.3 数组的使用
在数组的使用上主要是对数组的遍历,打印数组内容,反转数组进行讲解,其中遍历数组使用for循环就可以做到,在这里不做过多陈述。打印数组内容和遍历数组输出结果基本一致,这个内容可以作为一个方法被调用到主函数中。反转数组在一些题目上,算法上很容易用到,要对反转操作了熟于心。
5.3.1 打印数组内容
public static void printArray(int[] arrays) {
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i] + "");
}
}
<需要注意的是,方法中需要传入数组类型和名称,在调用中需要把要打印内容的名称输入在括号里>
5.3.2 反转数组
反转数组作为一个重要方法,它在c++语法和数据结构中的顺序表,链表等结构体也有应用,也会出考题,需要格外注意,理解上需要花费心思。
public static int[] reverse(int[] arrays) {
int[] result = new int[arrays.length];
//反转的操作
for (int i = 0,j = result.length-1; i < arrays.length; i++,j--) {
result[j] = arrays[i];
}
return result;
}
reverse方法中返回的是一个int类型的数组,先定义一个result的int类型的数组来接受反转后的数组内容,反转操作中也用两个变量,一个顺序i和一个逆序j分别对数字内容进行对应的存储,它们类似于函数的一一对应关系,其中要重点回想起数组的下标是从0开始的,所以会出现j = result.length-1,因为i和j都表示的是下标,并通过下标来输出数组内容。接下来i++和j--都是对应的,最后再将原数组的内容依次赋值给反转数组,最后返回result,再用printArray(result);在主函数中调用。
5.3.3数组
多维数组本质上是对数组的多层嵌套,“数组套着数组”,数组里面从装着数变成了装着数组,三维四维数组多是如此,在这里就不会详细介绍了,只要了解到多维数组的本质就可以了。
二维数组图片展示:
二维数组通常伴随着坐标轴出现,因为二维数组的二维性可以很好的展现出在坐标轴上x与y的数值,更好的反应一个点的坐标,所以在以后会出现的坐标轴类似的问题,要首先想到二维数组的适用性,如果可以很快地想到,那么数组这关便轻松的过了。
public static void main(String[] args) {
int[][] a = {{1,2},{3,4},{5,6},{7,8}};
//printArray(a[0]);
System.out.println(a[0][0]);//1
System.out.println(a[0][0]);//1
}
5.3.4组的遍历
关于多维数组的遍历是通过for循环的嵌套来实现的,其中要注意数组长度的分别调用.
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
System.out.println(a[i][j]);
}
}
5.4 Arrays类
首先,这个类是数组的专用工具类java.util.Arrays,是API中提供给我们使用的工具类,可以对数据对象进行一些简单的基本操作。另外,此类中的方法都是static修饰的静态方法,使用的时候可以直接使用类名进行调用,而“不用”使用对象来调用(注意:是“不用“而不是“不能”)
---Arrays类具有以下常用功能:
- 给数组赋值:通过fill方法
- 对数组排序:通过sort方法(按升序)
- 比较数组:通过equals方法比较数组中的元素值是否相等
- 查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作
- 打印数组内容:通过toString()方法直接打印
5.5 冒泡排序(八大排序中最出名的排序算法)
关于冒泡排序:
1.比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置
2.每一次比较,都会产出一个最大,或者最小的数字
3.下一轮则可以减少一次排序
4.依次循环,直到结束
冒泡排序的代码展示以及重要的解析:
public static void main(String[] args) {
int[] arr = { 1,34,23,5,7,0,34,15 };
int[] sort = sort(arr);//调用我们自己写的排序方法以后,返回一个排序后的数组
System.out.println(Arrays.toString(sort));
}
public static int[] sort(int[] array) {
/*临时变量,用temp来存储要交换的值,是原来的位置空起来,再将比大小后的结果存放进去,
最后将temp里的内容放回上一个交换值的原位上*/
int temp = 0;
//外层循环,判断我们这个循环要走多少次
for (int i = 0; i < array.length-1; i++) {//-1是为了不让循环溢出(下标)
//内层循环,比较两个数,如果第一个数字比第二个数字大,则需要交换位置
for (int j = 0; j < array.length-1-i; j++) {
if (array[j+1] > array[j]) {//降序:由大到小;将<换成>就是由小到大
temp = array[j];//从这里将位置为j的数组里的数值放入temp中,j数组为空
array[j] = array[j+1];//将后一位数值放到j位置的数组中,j+1为空
array[j+1] = temp;//将temp里的值放到j+1中,temp又变回空或者说0
}
}
}
return array;
在冒泡排序这个嵌套循环中,这个算法的时间复杂度为O(n2)。
<在排序算法中,最后一遍可以被省略,通过boolean在循环里面判断最后一次排序,再用if语句对最后一次循环使用break,跳出循环即可优化一次,节省时间和资源。>
6.面向对象编程的思想
6.1 初始面向对象(oop)
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
三大特性:封装,继承,多态
6.1.1 方法的返回值初始化
【作者说:在这一方面,我初学时有很深的误解,很容易混淆对象名与类名,这个格式的内容是与Scanner的new格式是一样的,要深刻记住调用方法的需要返回值或者是void不需要返回值,以及return的用法】
public static void main(String[] args) {
//若要调用的方法无 static,则需要在main中实例化这个对象,才可继续调用
Demo1 demo1 = new Demo1();//类名 对象名(任意名称,见名知意) = new 类名
//需要注意的是:对象名.方法名()不需要static,类名.方法名()必须加上static,要注意
区分对象名(demo1)与类名(Demo1)
demo1.max(1,2);
//int max = Demo1.max(1,2);这种方法需要在下面的方法类中加上static,属于静态方法的调用
System.out.println(demo1.max(1,2));
}
public int max(int a , int b){
return a > b ? a : b;//三元运算符,这个返回值不会打印出来,这是向电脑返回
}
6.2 类与对象的关系(抽象与具体的关系)
类是一种数据类型,它是对某一类事物整体的描述和定义,但并不能代表某一个具体的事物。
对象是抽象概念的具体实例,它能够体现出特点,展现出功能。
类中具有构造器(构造方法),是在进行创建对象的时候必须要调用的,并且它具有以下的两个特点:
1.必须和类的名字相同
2.必须没有返回值类型,也不能写void
对象的引用:对象通过引用来操作,由栈指向堆(地址)
属性:属性需要默认的初始化
数字:0 0.0
char: u0000
boolean: false
引用: null
6.2.1 对象的创建和使用
--必须使用new 关键字创造对象,构造器 Person wzs = new Person();
--对象的属性 wzs.name
--对象的方法 wzs.sleep()
6.3 Java的三大特性
6.3.1 封装
封装就是该露的露,该藏的藏,对内隐藏细节,对外暴露接口。程序设计追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅仅暴露少量的方法给外部使用。
需记住:private属性私有,get/set
封装的类代码:
public class Student {
private String name;
private int age;
private int id;
private char sex;
//当属性私有后,无法在main方法中调用这些属性,我们需要使用一些public的get和set方法
//get 获得这个数据
public String getName(){
return this.name;
}
//set 给这个数据设置值
public void setName(String name){
this.name = name;
}
}
封装的执行代码(main):
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
//s1.name = "";这种方法不可行,需要用get和set方法
s1.setName("天下云");
System.out.println(s1.getName());
}
}
输出结果:天下云
<对于一些错误或不合理的传入值,封装可以很好地解决这类问题。比如传入年龄值999,那么这个值是不合法的,可以在年龄的setAge(){}方法中进行一个对age范围的判断,可以有效解决这类问题。而且在后面继承思想中,也会使用get/set方法,因为大多数继承都会使用Private来私有化属性>
方法的重载:对于同一个类中,允许存在方法名相同,但参数列表不同的多个方法,调用时会根据传入参数的类型自动匹配对应方法。它可以很好的简化命名,简化调用,只需要传入参数就可以自动匹配,提升代码的复用性和可读性。
6.3.2 继承
继承就是对某一批类的抽象,从而实现对现实世界更好的建模。
extends的意思是"扩展".子类是父类的扩展。java中只有单继承吗,没有多继承!
子类只要继承了父类,就会继承父类所有的方法!
在继承关系的两个类中,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示,子类与父类从意义上讲应该具有"is a"的关系。
父类:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
子类:
public class Student extends Person{
private String school;
public String getSchool() {
return school;
}
public void setSchool(String school){
this.school = school;
}
<对于上述代码,如果只测试父类的话只能传入名字和年龄(属于Person类),通过继承后的子类Student,测试后可以传入名字,年龄和学校,这是因为子类继承了父类的前面两个属性,就可以直接调用,但要注意调用方法的区分,不能弄混淆了>
在java中,所有的类,都默认直接或间接继承Object(在创建的子类或父类中同时点击键盘ctrl+h,将会弹出以下这个窗口,可以清晰直观的看出子类和父类的关系)
6.3.2.1 super:是一个关键字,用于在子类中访问父类的属性或者方法
对于属性而言,直接调用,this调用和super调用,这三种调用方法在控制台生成的结果是大不相同的;
name是调用方法传入的参数,也就是在main方法中传入的参数"秦疆"
this.name是调用本类中的传入name"qinjiang"
super.name是调用在子类中传入的name参数"kuangshen"
对于方法而言,super的用法与上述属性基本一致,在此不作过多阐释
super调用构造方法要注意:
1.super调用父类的构造方法,必须在构造方法中的第一个
2.super必须只能出现在子类的方法或构造方法中
3.super和this不能同时调用构造方法
vs this:
1.代表的对象不同
this: 本身调用着这个对象
super: 代表父类对象的引用
前提:
this:没有继承也可以使用
super: 只能在继承条件下使用
调用构造方法:
this();本类的构造
super();父类的构造
6.3.2.2 方法的重写(只是方法的重写,与属性无关)
一、基本概念
方法重写:子类继承父类后,重新定义父类中已有的方法,保留方法声明,修改方法体,实现子类专属逻辑。
快捷键重写:Alt + Insert : override;
核心:声明不变,实现改变
二、重写的5大规则(必记)
1. 方法名、参数列表、返回值类型 必须和父类完全一致(区分重写与重载)
2. 访问权限:子类方法权限 ≥ 父类方法权限 (范围可以扩大)
(public > protected > 默认 > private)
3. 父类private、static、final 方法不能被重写
4. 重写方法不能抛出比父类更宽泛的异常,范围可以被缩小,不能被扩大
5. 必须发生在继承关系中,子类重写父类的继承
三、重写 vs 重载(核心区别)
| 特性 | 方法重写(Override)------方法重载(Overload) |
|---|---|
| 位置 | 子类与父类之间 -------------同一个类中 |
| 方法名 | 必须相同 ----------------------必须相同 |
| 参数列表 | 必须相同---------------------- 必须不同 |
| 返回值 | 必须相同 ------------------------无要求 |
| 修饰符 | 权限不能缩小 -------------------无要求 |
四、关键字使用
1. @Override:注解,强制校验是否符合重写规则,推荐必加
2. super.方法名():子类中调用父类被重写的原方法
五、适用场景
父类方法无法满足子类需求时,保留方法名,重写逻辑实现差异化功能。
6.3 多态
多态就是同一方法可以根据发送对象的不同而采取多种不同的行为方式。
多态存在的条件:
1.有继承关系
2.子类重写父类方法
3.父类引用指向子类对象 Father f1 = new Son();
多态相关代码和知识点要义:
多态注意事项:
1.注意:多态是方法的多态,属性没有多态性。
2.父类和子类有联系,否则会类型转换异常!名称:ClassCastException!
关键字:instanceof:判断两个类之间是否存在父子类的关系
(X instanceof Y)能不能编译通过?如果能,则X与Y为父子关系。若不能,则他们不是父子关系。
类型转换时,高转低需要强制转换,转换类型是为了父类可以运用子类的方法
知识点梳理:
1.父类引用指向子类的对 Person person=student,把子类student转成Person父类的一个对象person
2.把子类转换成父类,向上转型
3.把父类转换成子类,向下转型:强制转换,会丢失一些方法
4.方便一些方法的调用,减少重复的代码!简洁
6.4 抽象类
abstract修饰符可以修饰方法也可以修饰类;抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类;这个抽象类是不能用new关键字来创建对象的,它是用子类来继承的;抽象方法只有方法的实现,它是用来让子类来实现的;子类继承抽象类那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
//抽象类
public abstract class Action {
//抽象方法,只有方法名字,没有方法实现
public abstract void doSomething();
}
//抽象类的所有方法,继承它的子类,都必须要实现它的方法
//除非这个类也是一个抽象类,public和class之间有abstract修饰
public class A extends Action{
@Override
public void doSomething() {
//抽象类需要继承来实现,用extends,但是这个继承只能是单继承,有一定局限
//接口可以实现多继承
/*1.不能new这个抽象类,只能靠子类去实现它;约束!
2.抽象类中可以写普通的方法
3.抽象方法必须在抽象类中
4.抽象的抽象:约束!
* */
}
}
6.5 接口
接口的本质是契约,接口声明的关键字是interface
1. 关键字: interface 定义接口,** implements** 类实现接口 3. 本质:公开的规范、纯行为约定,无属性归属
3. 方法:默认 public abstract 抽象方法,无方法体
4. 成员变量:默认 public static final 常量
5. 无构造方法,不能实例化(不能new)
6. 支持多实现:一个类可同时实现多个接口,用逗号分隔
7. 必须重写:实现接口后,必须重写所有抽象方法
8. 接口可多继承:接口 A 能同时继承接口 B、C
9. 作用:解决 Java 类单继承局限,解耦、扩展能力
//interface 定义的关键字,接口都需要有实现类(接口名后面加Impl)
public interface UserService {
//接口里面不能写方法,接口里的所有定义都是抽象的 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
public interface TimeService {
void timer();
}
//抽象类 : 单继承
//类 可以实现接口 implements 接口
//利用接口实现多继承 重写UserService , TimeService两个方法
public class UserServiceImpl implements UserService , TimeService{
@Override
public void update(String name) {
}
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void timer() {
}
6.6 内部类
内部类就是在一个类的内部再定义一个类(内部的类)
主要包括:成员内部类,静态内部类,局部内部类,匿名内部类
//外部类
public class Outer {
private int x = 10;
public void out(){
System.out.println("这是外部类的方法");
}
class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
//获得外部类的私有属性
public void getx(){
System.out.println(x);
}
}
}
public class Application {
public static void main(String[] args) {
//外部类通过new方法来实现
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.getx();//内部类可以获得外部类的私有属性
inner.in();
}
}
Java 内部类 核心笔记
- 定义在另一个类 内部 的类
- 关键字还是 class ,只是写在别的类 {} 里面
- 可以直接访问外部类的所有成员(包括 private)
2. 四种内部类
① 静态内部类(static 修饰)
- 用 static class 写在类里
- 不依赖外部对象,像个独立工具类
- 理解:英雄的通用技能模板,不需要具体英雄就能用
② 成员内部类(不加 static)
- 写在类里、方法外
- 必须依附外部对象才能用
- 理解:这个英雄专属的连招、专属技能,别的英雄用不了
③ 局部内部类(方法里的类)
- 写在方法里面
- 作用域只在这个方法里
- 理解:这一波团战的临时连招,打完就没用了
④ 匿名内部类(最重要!)
- 没有名字的内部类
- 用来快速实现接口 / 抽象类
- 不用单独写一个类,直接 new 接口/父类
- 理解:现场编一套连招,当场用、当场执行
- 内部类最核心作用
1. 更好的封装:把只给外部类用的类藏起来
2. 方便访问外部私有成员
3. 简化接口/抽象类的使用(特别是匿名内部类)
4. 解决 Java 单继承的小局限
6.7 异常 (Exception)
异常通常是指在程序运行中出现一些不期而至的各种状况:如文件找不到,网路连接不上,非法参数等。
异常的分类:
1.检查性异常:由于用户出现错位或问题引起的异常,这是程序员无法预见的。
2.运行时异常:运行时异常是可能被程序员避免的异常,可以在编译时被忽略。
3.错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常会被忽略。例如,当栈溢出时,一个错误就发生了,他们在编译时也检查不到的。
//异常代码展示:
public class Deom1 {
public static void main(String[] args) {
System.out.println(100/0);//o不能做被除数
}
}
运行结果展示:
异常的分支:
捕获和抛出异常:(键盘快捷键Crtl+Alt+T)
1.try关键字:在try所在的区域称为监控区(必需)
2.catch关键字:用来捕获异常(必需)
3.finally关键字:不管程序里有没有异常,程序仍要执行,处理善后工作(可选)
4.throw关键字:如果意识到明显错误,用if语句把错误条件表示在小括号里,在大括号里抛出异常,一般在方法中使用,对于方法而言,如果方法处理不了这个异常,那么就在方法上抛出这个异常。
关于抛出异常throw的用法:
关于异常关键字的用法:
实际应用中处理异常:
【作者说:恭喜你,你已经掌握了基本的JavaSE课程,也同样恭喜我完成这段奋进向上,有始有终的时光。接下来Java的大门正式打开,我相信我现在的所作所为是具有非凡的意义的,我正在为未来的我完成一份扎实且重要的背书,希望各位学者仍大步向前,你我共勉这段征程。学无止境,志在远方,心有所属,必当向往。】