以后工作想向 Java Web 发展,有很多需要学习的。但是已经很久很久没有摸过Java了,那就从Java复习开始吧。目前跟着狂神进行一个学习,写写笔记给自己记录一下吧。
(翻了翻先前的笔记才发现我竟然也是学过Java的人诶!)
一、基础部分
基础知识几乎所有语言通用,也都还记得些,就整一些自己可能会忘记的。
1.基本数据类型
//整数
int num1 = 10;
byte num2 = 20;
short num3 = 30;
long num4 = 40L; //long类型要在数字后加个L
//小数
float num5 = 50.1F; //float类型要在数字后加个F
double num6 = 3.1415926;
//字符
char name1 = 'a';
String name2 = "张三"; //String不是关键字,是类
//布尔值,只有true和false
boolean flag1 = true;
boolean flag2 = false;
2.常量与变量
常量用 final 修饰;
变量有三种:类变量、实例变量、局部变量。
public class Main {
//常量 final:为修饰符,不存在先后顺序
//即 static 和 final 位置可互换
static final double PI = 3.14;
//实例变量:从属于对象;若不进行初始化,则为默认值
String name;
int age;
boolean flag;
//类变量 static
static double salary = 2500;
//main方法
public static void main(String[] args) {
//常量
System.out.println(PI);
//局部变量:在main方法里,使用前必须声明和初始化
String str = "Hello World";
System.out.println(str); //局部变量定义了就能用
//实例变量:变量类型 变量名字 = new ActionScope();
ActionScope actionScope = new ActionScope();
System.out.println(actionScope.age);
System.out.println(actionScope.name);
System.out.println(actionScope.flag);
//类变量 static
System.out.println(salary);
}
//其他方法
public void other() {
}
}
3.移位运算符
直接与计算机底层打交道,效率极高。
例如:计算 2^3,即 2 * 2 * 2。计算机通过将 0000 0010 (二进制)左移3位,得到 0001 0000(二进制),即算得结果为16(十进制)。
public class Main {
public static void main(String[] args) {
/*
A = 0011 1100
B = 0000 1101
---------------------------------
A & B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~ B = 1111 0010
---------------------------------
<< 左移
>> 右移
*/
System.out.println(2<<3);
System.out.println(14>>2);
}
}
第一个输出结果为16不再做解释,第二个输出为3。
14(十进制)= 0000 1110
右移两位后:0000 0011
最后一个1超出边界了,不要它了!所以转换为十进制后得到结果为3。
二、流程控制
一些流程控制,条件分支、循环等等,也仅仅记录一些自己会遗忘的。
1. next ( ) 与 nextLine ( )
next ( ):以空格和回车为结束标志。例:输入Hello World,输出为Hello。
nextLine ( ):仅以回车为结束标志。例:输入Hello World,输出为Hello World。
2.switch
JDK7之后支持String类型的比较了
记录switch是因为在idea上发现了一些好玩的东西,先前用eclipse时没有提示。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String grade = scanner.nextLine();
switch (grade) {
case "A" -> System.out.println("优秀");
case "B" -> System.out.println("良好");
case "C" -> System.out.println("及格");
case "D" -> System.out.println("不及格");
default -> System.out.println("未知等级");
}
scanner.close();
}
}
3.关于For循环的一道例题
代码本身比较简单,学到了点新的操作:输出1000.for,idea会自动生成for语句,上下界记得自行修改。
用for循环输出1-1000之内能被5整除的数,并且每行输出3个。
public class Main {
public static void main(String[] args) {
for (int i = 0; i <= 1000; i++) {
if(i % 5 == 0)
System.out.print(i + "\t");
//每行输出三个数字,即查找15个数字后换行
if(i % 15 == 0)
System.out.print("\n");
}
}
}
4.打印三角形
这题的思想特别妙,是从未设想过的道路,进行一个记录。
public class Main {
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();
}
}
}
运行结果:
* *** ***** ******* *********
三、方法
方法类似于C中的函数,写在类中,先前我们写的代码都是在main方法中的。自己编写新方法时,应与main方法保持并列的关系。注:Java都是值传递!
要开始认真学习了!先前学习的时候就有些一知半解。
1.简单加法
public class Main {
//main方法
public static void main(String[] args) {
int sum = add(1,2);
System.out.println(sum);
}
//加法,加static修饰后成为类变量,方便在主函数中调用
//后续学了对象之后再调整
public static int add(int a, int b){
return a + b;
}
}
2.比较大小
public class Main {
public static void main(String[] args) {
int max = compare(10, 10);
System.out.println(max);
}
//比较大小
public static int compare(int a, int b){
int result = -1; //建议将result初始化赋值,随便什么都可以
if(a == b)
return 0; //终止方法
if(a > b)
result = a;
else
result = b;
return result;
/*
一般而言,return写在最后,
if(xxx) return xxx;
else return xxx;
该写法不推荐!
*/
}
}
3.方法的重载
重载:在一个类中,有相同的函数名称,但形参不同的函数。(可以是参数类型不同,例如一个是double,一个是int;也可以是参数个数不同,例如一个含有2个参数,一个含有3个参数)
这里直接上图,看的清楚一些:
可以看到,方法名都是相同的,但参数个数与参数类型不同。在main方法中调用时,编译器会根据实参进行逐个匹配,选择正确的方法;如果匹配失败,则编译器会报错。
4.可变参数
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何方法的参数必须在它之前声明。
简单尝试:
public class Main {
public static void main(String[] args) {
Demo3 demo3 = new Demo3();
demo3.test(1,2,3,4,5); //此处可输出任意个int型数字
}
public void test(int ... i){
for (int j = 0; j < 5; j++) {
System.out.println(i[j]);
}
}
}
求最大值:
public class Main {
public static void main(String[] args) {
//调用可变参数的方法
printMax(34,3,3,2,56.5); //随意输入,只要为double都可以
}
public static void printMax(double... numbers){
if(numbers.length == 0){ //没有传参数
System.out.println("No argument passed");
return;
}
double result = numbers[0]; //定义返回值
//求最大值
for (int i = 1; i < numbers.length; i++) {
if(numbers[i] > result)
result = numbers[i];
}
System.out.println("The max value is:" + result);
}
}
5.递归
递归重要组成部分:
①递归头:什么时候不调用自身方法,也就是递归结束条件。如果没有递归出口,将会陷入死循环。
②递归体:什么时候需要调用自己。
如果能理解栈,那递归就好理解了,递归实质就是一个进栈出栈的过程。
阶乘(学一次递归就来一遍阶乘):
public class Main {
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n){
if(n == 1)
return 1;
else
return n * f(n - 1);
}
}
6.例题
写一个计算器,要求实现加减乘除功能,并且能够循环接收新的数据,通过用户交互实现。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
double a = scanner.nextDouble(); //接收第一个数字
String op = scanner.next(); //接收符号
double b = scanner.nextDouble(); //接收第二个数字
double result; //接收参数
switch (op) {
case "+" -> result = add(a, b);
case "-" -> result = minus(a, b);
case "*" -> result = multiple(a, b);
case "/" -> result = divide(a, b);
default -> result = -1; //接收到的op非+-*/中的一个
}
System.out.println(result);
}
scanner.close();
}
//加法
public static double add(double a, double b){
return a + b;
}
//减法
public static double minus(double a, double b){
return a - b;
}
//乘法
public static double multiple(double a, double b){
return a * b;
}
//除法
public static double divide(double a, double b){
return a / b;
}
}
四、数组
1.数组的基本特点
①数组的长度是确定的,一旦被创建,它的大小就不可以改变。
②其元素必须是相同类型。
③数组中的元素可以是任何数据类型,包括基本类型和引用类型。
④数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组对象本身是在堆中的。
2.静态初始化与动态初始化
动态初始化包含了默认初始化,即没有重新赋值过的元素默认值为0。
public class Main {
public static void main(String[] args) {
//静态初始化
int[] a = {0, 1, 2, 3, 4, 5};
for (int j : a) {
System.out.print(j + " ");
}
System.out.println();
//动态初始化,包含默认初始化
int[] b = new int[10];
b[0] = 10;
System.out.println("第一个元素是:" + b[0]);
System.out.println("第二个元素是:" + b[1]); //默认初始化为0
System.out.println("第三个元素是:" + b[2]); //默认初始化为0
}
}
3.数组基本操作
public class Main {
public static void main(String[] args) {
int[] a = {0,1,2,3,4,5};
//打印全部数组元素
for (int j : a) {
System.out.print(j + " ");
}
System.out.println("\n--------------------");
//计算所有元素和
int sum = 0;
for (int j : a){
sum = sum + j;
}
System.out.print("数组总和为:" + sum);
System.out.println("\n--------------------");
//查找最大元素
int max = a[0];
for (int i = 1; i < a.length; i++) {
if(a[i] > max){
max = a[i];
}
}
System.out.println("最大值是:" + max);
}
}
4.数组进阶操作
public class Main {
public static void main(String[] args) {
int[] arrays = {0,1,2,3,4,5};
//打印数组元素
printArrays(arrays);
//打印反转后的数组
int[] reverse = reverse(arrays);
printArrays(reverse);
}
//打印数组元素
public static void printArrays(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.print("原数组为:" + arrays[i] + " ");
}
System.out.println();
}
//反转数组
public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length];
for (int i = arrays.length - 1, index = 0; i >= 0; i--, index++) {
result[index] = arrays[i];
}
return result;
}
}
5.多维数组
打印多维数组,重点在第二个for循环的条件,j < array[i].length 是我从未设想过的套路,学到了。
public class Demo5 {
public static void main(String[] args) {
int[][] array = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j] + " ");
}
}
}
}
6.常用的Arrays类
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] array = {1,2,3,9,6,80,50,42,555,805,15,666};
System.out.println(array); //[I@16b98e56,是个对象
//打印数组元素,Arrays.toString方法
System.out.println(Arrays.toString(array));
//排序,升序
Arrays.sort(array);
System.out.println(Arrays.toString(array));
//数组填充,下标为2的元素到下标为4的元素被0填充,其余保持不变
Arrays.fill(array,2,4,-1);
System.out.println(Arrays.toString(array));
}
}
7.冒泡排序与简单优化
时间复杂度:O(n^2)
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] array = {1,5,6,9,2,10,7};
sort(array);
System.out.println(Arrays.toString(array));
}
/*
冒泡排序
比较数组中两个相邻元素,如果第一个数比第二个数大,则交换两者的位置
每一次比较都会产生一个最大或最小的数字
下一轮可以少一次排序
依次循环,直至结束
*/
public static void sort(int[] array){
int temp;
//外层循环,判断循环要走多少次,length-1防止溢出
for (int i = 0; i < array.length-1; i++) {
boolean flag = false; //通过flag标志位减少没有意义的比较
//内层循环,如果前一个数比后一个数大,则交换位置
for (int j = 0; j < array.length-1-i; j++) {
if(array[j+1] < array[j]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
flag = true;
}
}
if(!flag) //没有进行比较交换
break;
}
}
}
8.稀疏数组
概念:当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数组。
处理方式:
①记录数组一共有几行几列,有多少个不同值。
②把具有不同值的元素、所在行列、值记录在一个小规模数组中,从而缩小程序的规模,节省空间。
public class Main {
public static void main(String[] args) {
//创建一个二维数组 11*11 0:没有棋子 1:黑棋 2:白棋
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
//输出原始数组
System.out.println("打印原始数组:");
for (int[] ints : array1) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
System.out.println("====================");
//1.转换为稀疏矩阵保存
//获取有效值的个数
int sum = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (array1[i][j] != 0)
sum++;
}
}
System.out.println("有效值的个数:" + sum);
//2.创建一个稀疏数组的数组
int[][] array2 = new int[sum+1][3]; //int[a][b],a为有效数字+第0行,b固定为3(行、列、值)
array2[0][0] = 11; //行数
array2[0][1] = 11; //列数
array2[0][2] = sum; //有效数字个数
//3.遍历二维数组,将非零的值存入稀疏数组
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if(array1[i][j] != 0){ //找到非零的有效值
count++;
array2[count][0] = i; //存入横坐标
array2[count][1] = j; //存入纵坐标
array2[count][2] = array1[i][j]; //存入值
}
}
}
//4.输出稀疏数组
System.out.println("输出稀疏数组:");
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i][0] + "\t" + array2[i][1] + "\t" + array2[i][2]);
}
System.out.println("====================");
//5.还原稀疏数组
System.out.println("还原:");
//读取稀疏数组
int[][] array3 = new int[array2[0][0]][array2[0][1]];
//还原其中的元素
for (int i = 1; i < array2.length; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2];
}
for (int[] ints : array3) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
}
}
五、面向对象
面向对象编程的本质:以类的方式组织代码,以对象的形式组织(封装)数据。
核心思想:抽象
三大特性:封装。继承。多态
静态方法:类名 . 方法名
非静态方法(实例化对象):
①类名 对象名 = 对象值
②对象名 . 方法名
1.简单demo练习
ps:要写在一个package下
Application类:
public class Application {
public static void main(String[] args) {
//类:抽象的,需要实例化
//类实例化后会返回一个自己的对象
//student对象就是Student类的具体实例
Student student = new Student(); //实例化对象
student.name = "张三";
student.age = 18;
System.out.println(student.name + "今年" + student.age + "岁了!");
}
}
Student类:
//学生类,类中只有属性和方法
public class Student {
//属性:字段
String name;
int age;
//方法
public void study(){
System.out.println(this.name + "在学习"); //this代表当前类
}
}
2.构造器
打开.class文件:Ctrl + shift + alt + S,Add Content Root,选择out文件。
alt + insert会生成一个构造器。
特点:
①必须和类的名字相同。
②必须没有返回类型,也不能写void。
作用:
①使用new关键字,本质是在调用构造器。
②用来初始化值。
注意点:
定义有参构造之后,如果想继续使用无参构造,显示的定义一个无参的构造。
Application_Person类:
public class Application_Person {
public static void main(String[] args) {
//new实例化了一个对象
Person person = new Person();
System.out.println(person.name);
}
}
Person类:
public class Person {
//显示的定义构造器
String name;
//实例化初始值,无参构造器
public Person(){
this.name = "张三";
}
//有参构造器
public Person(String name){
this.name = name;
}
}
3.封装
大多数是对于属性,对方法应用的较少。
属性为private,不允许外部直接对属性进行修改。
但是提供一些 public 的 get 和 set 的外部方法,进而修改属性。get :获得这个数据;set:给这个数据设置值。
alt + insert 自动生成 get、set 方法
作用:
①提高程序安全性,保护数据
②影藏代码的实现细节
③统一接口
④增加系统的可维护性
Application类:
public class Application {
public static void main(String[] args) {
Student student1 = new Student();
student1.setName("张三");
System.out.println(student1.getName());
student1.setAge(888);
System.out.println(student1.getAge());
}
}
Student类:
public class Student {
//属性私有
private String name;
private int id;
private char sex;
private int age;
//提供get、set方法可以操作属性
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 120 || age < 0){
this.age = 999999;
}
else
this.age = age;
}
}
例如 age 这里,可以在 setAge 方法中判断修改的数据是否合法,保证了系统的安全性与数据的正确可靠。
4.继承
关键词:extends
①子类继承父类,就会拥有父类的全部方法(仅public修饰,private无法继承,除非使用 get 和 set)。
②在Java中,所有的类都默认继承Object类,即Object类是所有类的父类。
③在Java中,类只有单继承,没有多继承。即一个子类只能有一个父类,一个父类可以有多个子类。
Application类:
public class Application {
public static void main(String[] args) {
Student student = new Student();
Teacher teacher = new Teacher();
//public方法直接调用
//student与teacher均已继承Person中的全部属性与方法
student.say();
teacher.say();
//private属性用 get 获取
System.out.println(student.getMoney());
}
}
Person类(父类):
//Person,父类
public class Person {
private int money = 10_000_000;
public void say(){
System.out.println("说了一句话");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
Student类(继承自Person类):
//Student is Person,子类
public class Student extends Person{
}
Teacher类(继承自Person类):
//Teacher is Person,子类
public class Teacher extends Person{
}
关键词:super
①子类调用父类的属性或方法,必须在构造方法的第一个。
② super 必须只能出现在子类的方法或构造方法中。
③ super 和 this 不能同时调用构造方法。
Application类:
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.test("我是传入的张三");
}
}
Person类(父类):
//Person,父类
public class Person {
protected String name = "我是父类张三";
}
Student类(继承自Person类的子类):
//Student is Person,子类
public class Student extends Person{
private String name = "我是子类张三";
public void test(String name){
System.out.println(name); //传入的参数
System.out.println(this.name); //该类中定义的属性
System.out.println(super.name); //父类中的属性
}
}
输出结果:
我是传入的张三
我是子类张三
我是父类张三
重写
需要有继承关系,即子类重写父类的方法,且都是非静态方法的重写。
为什么需要重写?
父类的功能,子类不一定需要,或者不一定满足。
关键点:
①方法名必须相同。
②参数列表必须相同。
③方法体不同。
④修饰符范围可以扩大,但不能缩小:例如父类为 default ,子类重写为 public 等。范围private < default < protected < public。在重写中, private 不能使用!
⑤抛出的异常:范围可以缩小,但不能扩大。
注:静态方法和非静态方法区别很大!静态方法是类的方法(类的成员),非静态方法是对象的方法(对象的成员)。
Application类:
public class Application {
public static void main(String[] args) {
A a = new A();
a.test();
B b= new A();
b.test();
}
}
B类(父类):
public class B {
public void test(){
System.out.println("B=>test()");
}
}
A类(子类):
public class A extends B{
public void test(){
System.out.println("A=>test()");
}
}
输出结果:
A=>test()
A=>test()
5.多态
定义:即统一方法可以根据发送对象的不同而采取多种不同的行为方式。
可以实现动态编译,使可扩展性变得更强。
多态注意事项:
①多态是方法的多态,属性没有多态。
②存在于父类与子类中,只有父子之间才能转换,否则会出现类型转换异常。ClassCastException!
③存在条件:继承关系、方法重写、父类的引用指向子类对象。Father f1 = new Student ( ) ;
无法重写的三种情况(无法被重写,就更不可能实现多态):
① static 方法,属于类,不属于实例。
② final 表示修饰的是常量,不可被更改。
③ private 方法,无法被重写
Application类:
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//可以指向的引用类型不确定:父类的引用类型指向子类
Student s1 = new Student(); //能调用的方法是自己的,或继承自父类的
Person s2 = new Student(); //父类能指向子类,但不能调用子类独有的方法
Object s3 = new Student();
//对象能执行的方法,主要看对象左边的类型
s1.run();
s2.run(); //子类重写了父类的方法
s1.eat();
//s2.eat(); //s2的类型是Person,Person中没有eat方法
}
}
Person类:
public class Person {
public void run(){
System.out.println("FatherRun");
}
}
Student类:
public class Student extends Person{
@Override
public void run() {
System.out.println("SonRun");
}
public void eat(){
System.out.println("SonEat");
}
}
关键词:instanceof
用于判断两个类之间是否有父子关系。
这里就贴一个Application类,其他类之间的关系如注释:
public class Application {
public static void main(String[] args) {
//Object > Person > Student
//Object > Person > Teacher
//Object > String
Object object = new Student();
System.out.println(object instanceof Student); //true
System.out.println(object instanceof Person); //true
System.out.println(object instanceof Teacher); //false
System.out.println(object instanceof Object); //true
System.out.println(object instanceof String); //false
}
}
强制类型转换:
①父类引用指向子类的对象
②把子类转换为父类(向上转型),不用强制类型转换,直接进行。
③把父类转换为子类(向下转型),需要强制类型转换。
④方便方法的调用,减少重复的代码。
public class Application {
public static void main(String[] args) {
Person obj = new Student(); //此时的obj不能用Student类中的go()方法,Person > Student
((Student)obj).go(); //强制将Person类型的obj转化为Student类,即可调用go()方法
//子类转换为父类,可能丢失自己本来的一些方法
Student student = new Student();
student.go(); //正常调用go()方法
Person person = student; //低转高,可自动转化
}
}
6. static
静态属性:
public class Student {
private static int age; //静态变量
private double score; //非静态变量
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.age); //静态属性可直接通过 类.属性 进行调用
System.out.println(s1.score);
System.out.println(s1.age);
}
}
静态方法:
静态方法是与类一起加载的,类一旦存在,静态方法即存在。
(大白话理解:类是最先被加载的,静态方法同类一起被加载,所以静态方法出现的特别早;而非静态方法出现的相对较晚。)
所以,非静态方法可以访问静态方法,静态方法可以访问静态方法;静态方法不可以访问非静态方法!
(大白话理解:①非静态方法被加载时,静态方法早已和类一起被加载了,当然可以被调用;②静态方法都是与类一同被加载的,其之间当然可以互相调用;③静态方法加载时,非静态方法还没被加载呢,所以当然不能调用!)
static 可以扩大访问范围。
public class Student {
public void run(){
go();
}
public static void go(){
}
//main方法
public static void main(String[] args) {
//非静态方法:实例化对象后才能调用
Student student = new Student();
student.run();
//静态方法:两种方法均可,同一个类中推荐直接使用
student.go(); //能用,但不推荐
go(); //推荐使用
}
}
静态代码块:
public class Main {
//匿名代码块,静态代码块之后被加载
{
System.out.println("匿名代码块");
}
//静态代码块,最先被加载,只执行一次
static {
System.out.println("静态代码块");
}
//构造器,最后被加载
public Person() {
System.out.println("构造方法");
}
//main方法
public static void main(String[] args) {
Person p1 = new Person();
System.out.println();
Person p2 = new Person();
}
}
输出结果:
静态代码块
匿名代码块
构造方法
匿名代码块
构造方法
可以看到,执行顺序:静态代码块 > 匿名代码块 > 构造方法,但是静态代码块只执行一次。
静态导入包:
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Main {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
7.抽象类
关键词:abstract
①不能 new 这个抽象类,只能靠子类去实现它;就是个约束!
②抽象类中可以写普通方法。
③抽象方法必须在抽象类中。
Action类(抽象类,是父类):
//抽象类
public abstract class Action {
//约束,在子类中实现
//抽象方法,只有方法名字,没有方法的实现
public abstract void doSomething();
}
A类(继承自Action类,是子类):
//继承了抽象类的子类,必须实现原抽象类中的全部方法(除非子类也是抽象类)
//也就是子类对父类的重写
public class A extends Action{
@Override
public void doSomething() {
}
}
8.接口
关键词:
interface(定义接口)
implements(实现接口)
普通类:只有具体实现。
抽象类:具体实现和规范(抽象方法)都有,只是不能 new ,需要子类去操作。
接口:只有规范,自己无法写方法。实现约束和实现分离。
接口的本质是契约,是 OO 的精髓,是对对象的抽象。
接口不能被实例化,因为接口中没有构造方法。
interface 与 abstract:
①abstract:抽象类,通过 extends 单继承,然后进行实现(重写)。
②interface:接口类,通过 implements 多继承,然后进行实现(重写)。
UserService类(使用 interface 定义接口):
//interface 需要有实现类
public interface UserService {
//属性默认为常量 public static final
int age = 99;
//接口中的所有定义的方法默认都是抽象的 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
TimeService类(使用 interface 定义接口):
public interface TimeService {
void timer();
}
UserServiceImpl类(使用implements实现 UserService 与 TimeService 两个接口):
//使用implements实现接口
public class UserServiceImpl implements UserService, TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
9.内部类
成员内部类:
内部类可以获取外部类的私有属性。
Application类,通过外部类来定义内部类:
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.in();
}
}
Outer类与其内部类Inner:
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类的方法");
}
//内部类
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
//获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
局部内部类:
public class Outer {
public void method() {
//局部内部类
class Inner {
public void in() {
}
}
}
}
匿名内部类:
是局部内部类的一种形式,也要写在方法里。
前提:存在一个类或者接口,这里的类可以使具体类也可以是抽象类。
本质:是一个继承了该类或者实现了该接口的子类匿名对象。
格式(就是个对象):
new Inner(){ //Inner是接口名
@Override
public void show() { //重写接口中的方法
System.out.println("匿名内部类");
}
}; //注意分号
Application 类:
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
Outer 类:
public class Outer {
public void method(){
new Inner(){
@Override
public void show() {
System.out.println("匿名内部类");
}
}.show(); //本质:对象调用了show方法
}
}
Inner 接口:
public interface Inner {
void show(); //抽象方法
}
六、异常机制
异常Exception:检查性异常、运行时异常
错误Error
快捷键:ctrl + alt + t
try:尝试,必须要有。
catch:捕获,必须要有。catch(想要捕获的异常类型)。
finally:无论有无异常都会执行的部分,可有可无。关闭 IO 流、资源等操作可以放在 finally 中。
throw:抛出
throws:抛出
简单异常捕获:
public class Main {
public static void main(String[] args) {
int a = 1;
int b = 0;
try { //监控区域 必须要
System.out.println(a/b);
}catch (ArithmeticException e){ //捕获异常 必须要
System.out.println("程序出现异常,变量b不能为0");
}finally { //处理善后工作,无论有无异常,都会执行 可以不要
System.out.println("finally");
}
}
}
输出结果:
程序出现异常,变量b不能为0
finally
若不使用异常捕获,则会出现如下报错:
多个异常捕获:
假设有多个异常要捕获,可以使用多个 catch ,必须从低到高层层递进。如果一开始就使用最高层级的 Throwable 进行捕获(一定能抓到异常),则后续的捕获不会被执行。
public class Main {
public static void main(String[] args) {
int a = 1;
int b = 0;
try { //监控区域
System.out.println(a/b);
} catch (Error e){
System.out.println("Error");
}catch (Exception e){
System.out.println("Exception");
}catch (Throwable t){
System.out.println("Throwable");
} finally { //处理善后工作,无论有无异常,都会执行 可以不要
System.out.println("finally");
}
}
}
后记:
差不多JavaSE就学到这里啦,后续可能会补充知识点啥的…吧?
路还很长,继续努力!