JAVA 基础知识复习 视频地址:
https://www.bilibili.com/video/BV12J41137hu?t=2607&p=80
相关笔记:
数据类型以及面试拓展 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class demo03 { public static void main (String[] args) { int i = 10 ; int i2 = 010 ; int i3 = 0x10 ; System.out.println(i); System.out.println(i2); System.out.println(i3); System.out.println("=================" ); float f = 0.1f ; double d = 1.0 / 10 ; System.out.println(f==d); System.out.println(f); System.out.println(d); System.out.println("=================" ); char c1 = 'a' ; System.out.println(c1); System.out.println((int )c1); char c3 = '\u0061' ; System.out.println(c3); System.out.println("=================" ); String sa = new String("hello world" ); String sb = new String("hello world" ); System.out.println(sa==sb); System.out.println("=================" ); String sc = "hello world" ; String sd = "hello world" ; System.out.println(sc==sd); } }
类型转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class demo04 { public static void main (String[] args) { int i = 128 ; byte b = (byte ) i; System.out.println(i); System.out.println(b); System.out.println("===========" ); System.out.println((int )23.7 ); System.out.println((int )-45.89f ); System.out.println("===========" ); char c = 'a' ; int d = c + 1 ; System.out.println(d); System.out.println((char ) d); } }
溢出的问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class demo5 { public static void main (String[] args) { int money = 10_0000_0000 ; int years = 20 ; int total = money * years; long total2 = money * years; long total3 = money * (long ) years; System.out.println(total); System.out.println(total2); System.out.println(total3); } }
变量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class demo08 { static double salary = 2500 ; String name; int age; public static void main (String[] args) { int i = 10 ; System.out.println(i); demo08 Demo08 = new demo08(); System.out.println(Demo08.age); System.out.println(Demo08.name); System.out.println(salary); } public void add () { } }
位运算(效率考虑) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package operator;public class Demo06 { public static void main (String[] args) { System.out.println(2 <<3 ); } }
字符串操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package operator;public class Demo07 { public static void main (String[] args) { int a = 10 ; int b = 20 ; a += b; a -= b; System.out.println(a); System.out.println("" + a + b); System.out.println(a + b + "" ); } }
三元运算符(if的更简单的写法形式) 1 2 3 4 5 6 7 8 9 10 11 package operator;public class Demo08 { public static void main (String[] args) { int score = 80 ; String type = score < 60 ? "不及格" :"及格" ; System.out.println(type); } }
javadoc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.yuxuan.base;public class Doc { String name; public String test (String name) throws Exception { return name; } }
Scanner 对象 Next():
1. 一定要读取到有效字符后菜可以结束输入
2. 对输入有效字符之前遇到的空白,next()会将其自动去掉
3. 只有输入有效字符后才讲其后面输入的空白作为分隔符或者结束符号
4. next()不能得到带有空格的字符串
nextLine():
以enter作为结束符号,也就是说nexline()方法返回的是回车之前的字母
可以获得空白
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.yuxuan.scanner;import java.util.Scanner;public class Demo01 { public static void main (String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("使用next方式来接受: " ); if (scanner.hasNext()){ String str = scanner.next(); System.out.println("输出内容是: " +str); } scanner.close(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.yuxuan.scanner;import java.util.Scanner;public class Demo02 { public static void main (String[] args) { System.out.println("使用nextLine方式来接受: " ); Scanner scanner = new Scanner(System.in); if (scanner.hasNextLine()){ String s = scanner.nextLine(); System.out.println("输出的内容为:" + s); } scanner.close(); } }
Switch case 语句 注意case的穿透特性,建议加上break
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package com.yuxuan.struct;public class SwitchDemo { public static void main (String[] args) { char grade = 'c' ; switch (grade){ case 'a' : System.out.println("优秀" ); break ; case 'b' : System.out.println("良好" ); break ; case 'c' : System.out.println("及格" ); break ; case 'd' : System.out.println("再接再厉" ); break ; default : System.out.println("未知等级" ); } } }
方法(methods) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.yuxuan.method;public class Demo01 { public static void main (String[] args) { int max = max(10 , 20 ); System.out.println(max ); } public static int max (int num1, int num2) { int result = 0 ; if (num1 == num2) { System.out.println("num1==num2" ); return 0 ; } if (num1 > num2) { result = num1; } else { result = num2; } return result; } }
Java 都是值传递
方法的重载(overload)
重载就是在一个类中,有相同的函数名称,但是形式参数不同的函数
方法的重载规则:
方法名称必须相同
参数列表必须不同(个数不同,或者类型不同,参数排列顺序不同等)
方法的返回类型可以相同也可以不相同
仅仅返回类型不同不足以成为方法的重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class Overloading { public int test () { System.out.println("test1" ); return 1 ; } public void test (int a) { System.out.println("test2" ); } public String test (int a,String s) { System.out.println("test3" ); return "returntest3" ; } public String test (String s,int a) { System.out.println("test4" ); return "returntest4" ; } public static void main (String[] args) { Overloading o = new Overloading(); System.out.println(o.test()); o.test(1 ); System.out.println(o.test(1 ,"test3" )); System.out.println(o.test("test4" ,1 )); } }
命令行传参数 1 2 3 4 5 6 7 8 9 10 package com.yuxuan.method;public class Demo03 { public static void main (String[] args) { for (int i = 0 ; i < args.length; i++) { System.out.println("args[" + i + "]: " + args[i]); } } }
先用javac 打包成一个class文件
然后注意要退回到src文件才可以调用,因为里面有一个包的成分
可变参数 在方法声明中,在指定参数类型后加一个省略好(…)
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数,任何普通的参数都必须在它之前声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.yuxuan.method;public class Demo04 { public static void main (String[] args) { printMax(34 , 3 , 3 , 2 , 56.5 ); printMax(new double []{1 , 2 , 3 }); } public static void printMax (double ... numbers) { if (numbers.length == 0 ) { System.out.println("no argument passed" ); return ; } double result = numbers[0 ]; for (int i = 0 ; i < numbers.length; i++) { if (numbers[i] > result) { result = numbers[i]; } } System.out.println("The max value is " + result); } }
递归:
递归头:什么时候不调用自身方法 。如果没有头,就会陷入死循环
递归体:什么时候需要调用自身的方法
基数比较小的数字建议用递归,如果数字太多,会出现压栈,然后内存溢出
数组
数组是相同类型数据的有序集合
数组描述的是相同类型的若干数据,按照一定的先后次序排列组合而成
其中一个数据称作一个数组元素,每个数组元素可以通过一个下标来进行访问(从0开始)
数组的声明以及创建
首先必须声明数组变量,才能在程序中使用数组
java使用new来创建数组
数组的元素是通过索引来进行访问的,数组索引从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.yuxuan.array;public class ArrayDemo01 { public static void main (String[] args) { int [] nums; nums = new int [10 ]; nums[0 ] = 1 ; nums[1 ] = 2 ; nums[2 ] = 3 ; nums[3 ] = 4 ; nums[4 ] = 5 ; nums[5 ] = 6 ; nums[6 ] = 7 ; nums[7 ] = 8 ; nums[8 ] = 9 ; nums[9 ] = 10 ; int sum = 0 ; for (int i = 0 ; i < nums.length; i++) { sum = sum + nums[i]; } System.out.println(sum); } }
内存分析
Java 内存
堆:
存放new的对象和数组
可以被所有的线程共享,不会存在别的对象引用
栈:
存放基本变量类型(包含这个基本类型的具体数值)
引用对象的变量(会存放这个引用在堆里面的具体地址)
方法区:
可以被所有的线程共享
包含了所有的class和static的变量
数组的默认初始化
- 数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也会被按照实例变量同样的方式被隐式初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.yuxuan.array;public class ArrayDemo02 { public static void main (String[] args) { int a[] = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 }; int [] b = new int [10 ]; b[0 ] = 10 ; System.out.println(b[0 ]); System.out.println(b[1 ]); System.out.println(b[2 ]); System.out.println(b[3 ]); } }
数组的四个基本特点
其长度是确定的。数组一旦被创建,它的大小就是不可以被改变的
其元素必须是相同类型的,不允许出现混合类型
数组中的元素可以是任何数据类型,包括基本类型和引用类型
数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,java 的对象都是在堆中的,因此数组无论保存原始类型 还是其他对象类型 ,==数组对象本身是在堆中的==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.yuxuan.array;public class ArrayDemo04 { public static void main (String[] args) { int [] arrays = {1 ,2 ,3 ,4 ,5 }; int [] reverse = reverse(arrays); printArray(reverse); } public static void printArray (int []arrays) { for (int i = 0 ; i < arrays.length; i++) { System.out.print(arrays[i] + " " ); } } 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; } }
多维数组 多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其中每一个元素都是一个一维数组
1 2 int a[][] = new int [2 ][5 ]
Arrays 类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.yuxuan.array;import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;import java.lang.reflect.Array;import java.util.Arrays;public class ArrayDemo06 { public static void main (String[] args) { int [] a = {1 , 2 , 3 , 9090 , 32132 , 543 , 21 , 3 , 23 }; System.out.println(Arrays.toString(a)); Arrays.sort(a); System.out.println(Arrays.toString(a)); Arrays.fill(a,0 ); System.out.println(Arrays.toString(a)); } }
冒泡排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.yuxuan.array;import java.util.Arrays;public class ArrayDemo07 { public static void main (String[] args) { int [] a = {1 , 2 , 3 , 5 , 22 , 34 , 56 }; int [] sort = sort(a); System.out.println(Arrays.toString(sort)); } public static int [] sort(int [] array ) { int tmp = 0 ; for (int i = 0 ; i < array.length - 1 ; i++) { boolean flag = false ; for (int j = 0 ; j < array.length-1 -i; j++) { if (array[j + 1 ] < array[j]) { tmp = array[j]; array[j] = array[j + 1 ]; array[j + 1 ] = tmp; flag = true ; } if (flag == false ) { break ; } } } return array; } }
我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为O(n2)
稀疏数组
当一个数组大部分的元素为0,或者为同一值的数组时候,可以用稀疏数组来保存该数组
稀疏数组的处理方式一般是:
记录数组一共有几航几列,有多少个不同的值
把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package com.yuxuan.array;public class ArrayDemo08 { public static void main (String[] args) { int [][] array1 = new int [11 ][11 ]; array1[1 ][2 ] = 1 ; array1[2 ][3 ] = 2 ; for (int [] ints : array1) { for (int anInt : ints) { System.out.print(anInt + "\t" ); } System.out.println(); } 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); int [][] array2 = new int [sum + 1 ][3 ]; array2[0 ][0 ] = 11 ; array2[0 ][1 ] = 11 ; array2[0 ][2 ] = sum; 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]; } } } System.out.println("==========" ); 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("==========" ); 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(); } } }
面向对象编程
面向过程思想 (线性思维)
步骤清晰简单,第一步做什么第二部做什么
面对过程适合处理一些较为简单的问题
面向对象思想
物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些类进行单独思考,最后才对某个分类下的细节进行面向过程的思索
面向对象适合处理复杂的问题,适合处理需要多人协作的问题
属性+方法就是一个类
对于描述复杂的事物,为了从宏观上进行把握,从整体上进行合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到围观操作,荏苒需要使用面向过程的思路来进行处理
OOP本质:==以类的方式组织代码,以对象的组织(封装)数据==
三大特性:
从认识角度考虑是先有对象,后有类
对象,是具体的事物
类,是抽象的,是对对象的抽象
类是一种抽象的数据类型,它是对某一类食物的整体描述/定义,但是并不能代表某一个具体的事物
动物,植物,手机,电脑
Person 类,Pet类,Car类,这些类是用来描述/定义某一类具体的事物应该具备的特点和行为
对象是抽象概念的具体实例
张三是人的一个具体实例,张三家里的旺财就是狗的一个具体实例
能狗体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.oop.demo01;public class Demo02 { public static void main (String[] args) { Student.say(); Student student = new Student(); student.say02(); } public static void a () { } public void b () { } }
1 2 3 4 5 6 7 8 9 10 11 12 package com.oop.demo01;public class Student { public static void say () { System.out.println("学生说话了" ); } public void say02 () { System.out.println("学生说话了" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.oop.demo01;public class Demo03 { public static void main (String[] args) { int add = Demo03.add(1 , 2 ); System.out.println(add); } public static int add (int a, int b) { return a + b; } }
值传递 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.oop.demo01;public class Demo04 { public static void main (String[] args) { int a = 1 ; System.out.println(a); Demo04.change(a); System.out.println(a); } public static void change (int a) { a = 10 ; } }
引用传递 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.oop.demo01;public class Demo05 { public static void main (String[] args) { Person person = new Person(); System.out.println(person.name); Demo05.change(person); System.out.println(person.name); } public static void change (Person person) { person.name = "yuxuan" ; } } class Person { String name; }
创建与初始化对象
使用new关键字创建对象
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及类中构造器的调用
类中构造器也被称为构造方法,实在进行穿件对象的时候必须要调用的。并且构造器有一下几个特点
必须和类的名字相同
必须没有返回类型,也不能写void
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.oop.demo02;public class Application { public static void main (String[] args) { Student student = new Student(); Student xiaoming = new Student(); System.out.println(xiaoming.age); System.out.println(xiaoming.name); xiaoming.name = "小明" ; xiaoming.age = 3 ; System.out.println(xiaoming.age); System.out.println(xiaoming.name); } }
构造器 构造器 1. 和类名相同 2. 没有返回值作用 1. new 本质在调用构造方法 2. 初始化对象的值注意点: 1. 定义有参构造后,如果想使用无参构造,显示的定义一个无参的构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package com.oop.demo02;public class Person { String name; public Person () { } public Person (String name) { this .name = name; } }
创建对象内存与分析 堆:存储对象和数组元素,栈:存储系统调用变量(例如引用)
堆:存放new的数组和对象,栈:存放基本变量类型和引用变量
静态方法 类加载过程中将静态变量,静态方法,常量存入到方法区
静态方法只执行一次
Final 后面断子绝孙
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.oop.demo07;public class Person { { System.out.println("代码快" ); } static { System.out.println("静态代码块" ); } public Person () { System.out.println("构造方法 " ); } public static void main (String[] args) { Person person = new Person(); Person person2 = new Person(); } }
作者:愚公要移山 链接:https://zhuanlan.zhihu.com/p/70110497 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Static 关键字
(1)特点:
1、static是一个修饰符,用于修饰成员。(成员变量,成员函数)static修饰的成员变量 称之为静态变量或类变量。
2、static修饰的成员被所有的对象共享。
3、static优先于对象存在,因为static的成员随着类的加载就已经存在。
4、static修饰的成员多了一种调用方式,可以直接被类名所调用,(类名.静态成员)。
5、static修饰的数据是共享数据,对象中的存储的是特有的数据。
(2)成员变量和静态变量的区别:
1、生命周期的不同:
成员变量随着对象的创建而存在随着对象的回收而释放。
静态变量随着类的加载而存在随着类的消失而消失。
2、调用方式不同:
成员变量只能被对象调用。
静态变量可以被对象调用,也可以用类名调用。(推荐用类名调用)
3、别名不同:
成员变量也称为实例变量。
静态变量称为类变量。
4、数据存储位置不同:
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据。
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
(3)静态使用时需要注意的事项:
1、静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
2、静态方法中不可以使用this或者super关键字。
3、主函数是静态的
类与对象的小结
类与对象
类是一个模版,对象是一个具体的实例
方法
定义,调用
对象的引用
引用类型:八大基本类型(8)
对象是通过引用来操作的:栈–》堆
属性:字段field 成员变量
默认初始化
数字: 0, 0.0
char: u0000
boolean:false
引用: null
修饰符 属性类型 属性名 = 属性值
对象的创建和使用
必须使用new 关键字创建对象 构造器 Person Yuxuan = new Person
对象的属性:yuxuan.name
对象的方法:yuxuan.sleep()
类
静态的属性 属性
动态的行为 方法
封装,继承,多态
封装 高内聚,低耦合
:
高内聚:类的内部数据操作细节自己完成,不允许外部干涉
低耦合:尽量暴露少量的方法给外部使用
封装
(数据的隐藏)
通常,应该禁止访问一个对象中数据的实际表示,而应该通过操作接口来进行访问,这称为信息的隐藏
==属性私有,get/set==
好处 :
提高程序的安全性,保护数据
隐藏代码的实现细节
统一接口
提高系统的可维护性
继承 extends
继承是类和类之间的关系
继承关系的两个类,一个是父类,一个是子类
在Java中,所有的类,都默认直接或者间接继承Object类
control+h 可以看结构
java类中只有单继承,没有多继承
私有的可以被继承,但拒绝被访问(无法继承)
调用弗雷德构造器,必须要在子类的第一行
1 2 3 4 5 6 7 8 9 10 11 12 package com.oop.demo05;public class Student extends Person { private String name = "dacy" ; public void test (String name) { System.out.println(name); System.out.println(this .name); System.out.println(super .name); } }
super 注意点
super调用父类的构造方法,必须在狗仔方法的第一个
super 必须只能出现在子类的方法或者构造方法中!
super 和this不能同时调用构造方式
VS this:
代表的对象不同:
this: 本身调用者的这个对象
super:代表父类对象的应用
前提
this:没有继承也可以使用
super:只能在继承条件下才可以使用
构造方法
this() 本类的构造
super() :父类的构造
重写 需要有继承关系,子类重写父类的方法!
方法名称必须相同
参数列表必须相同
修饰符:范围可以扩大:public>Protected>default>private
抛出的异常:范围,可以被缩小,但不能扩大:ClassNotFoundException –> Exception
重写,子类的方法和父类的必须要一致:方法体不同
为什么需要重写:
父类的功能,子类不一定需要,或者不一定满足!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.oop.demo05;public class Application { public static void main (String[] args) { A a = new A(); a.test(); B b = new A(); b.test(); } }
抽象 抽象概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package cn.itcast.day09.demo11;public abstract class Animal { public abstract void eat () ; }
1 2 3 4 5 6 7 8 9 10 package cn.itcast.day09.demo11;public class Cat extends Animal { @Override public void eat () { System.out.println("猫吃鱼" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 package cn.itcast.day09.demo11;public class DemoMain { public static void main (String[] args) { Cat cat = new Cat(); cat.eat(); } }
关于抽象类的使用,以下为语法上要注意的细节,虽然条目较多,但若理解了抽象的本质,无需死记硬背。
抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有
意义。
抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.oop.demo08;public abstract class Action { public abstract void doSomething () ;}
接口 本质:契约
接口:interface
作用:
约束
定义一些方法,让不同的人实现
public abstract final
接口不能被实例化,接口中没有构造方法~
implements可以实现多个接口
必须要重写
接口中的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package cn.itcast.day10.demo01;public class Demo01Interface { public static void main (String[] args) { MyInterfaceAbstractImpl impl = new MyInterfaceAbstractImpl(); impl.methodAbs1(); impl.methodAbs2(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package cn.itcast.day10.demo01;public interface MyInterfaceAbstract { public abstract void methodAbs1 () ; abstract void methodAbs2 () ; public void methodAbs3 () ; void methodAbs4 () ; }
接口使用步骤:
接口不能直接使用,必须有一个“实现类”来“实现”该接口。 格式: public class 实现类名称 implements 接口名称 { // … }
接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。 实现:去掉abstract关键字,加上方法体大括号。
创建实现类的对象,进行使用。
注意事项: 如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
默认方法Default default
关键字常常用于解决接口升级的问题,即新增一个抽象方法,不用去对应的实现类修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package cn.itcast.day10.demo01;public interface MyInterfaceDefault { public abstract void methodAbs () ; public default void methodDefault () { System.out.println("这是新添加的默认方法" ); } }
1 2 3 4 5 6 7 8 package cn.itcast.day10.demo01;public class MyInterfaceDefaultA implements MyInterfaceDefault { @Override public void methodAbs () { System.out.println("实现了抽象方法,AAA" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 package cn.itcast.day10.demo01;public class MyInterfaceDefaultB implements MyInterfaceDefault { @Override public void methodAbs () { System.out.println("实现了抽象方法,BBB" ); } @Override public void methodDefault () { System.out.println("实现类B覆盖重写了接口的默认方法" ); } }
Demo02-interface
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package cn.itcast.day10.demo01;public class Demo02Interface { public static void main (String[] args) { MyInterfaceDefaultA a = new MyInterfaceDefaultA(); a.methodAbs(); a.methodDefault(); System.out.println("==========" ); MyInterfaceDefaultB b = new MyInterfaceDefaultB(); b.methodAbs(); b.methodDefault(); } }
接口的静态关键词 注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。 正确用法:通过接口名称,直接调用其中的静态方法。 格式: 接口名称.静态方法名(参数);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package cn.itcast.day10.demo01;public interface MyInterfaceStatic { public static void methodStatic () { System.out.println("这是接口的静态方法!" ); } }
Final 关键字 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package cn.itcast.day10.demo01;public interface MyInterfaceConst { public static final int NUM_OF_MY_CLASS = 12 ; }
多继承
类与类之间是单继承的。直接父类只有一个。
类与接口之间是多实现的。一个类可以实现多个接口。
接口与接口之间是多继承的。
注意事项:
多个父接口当中的抽象方法如果重复,没关系。
多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,【而且带着default关键字】。
接口小结 在Java 9+版本中,接口的内容可以有:
成员变量其实是常量,格式: [public] [static] [final] 数据类型 常量名称 = 数据值; 注意: 常量必须进行赋值,而且一旦赋值不能改变。 常量名称完全大写,用下划线进行分隔。
接口中最重要的就是抽象方法,格式: [public] [abstract] 返回值类型 方法名称(参数列表);注意
:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。
从Java 8开始,接口里允许定义默认方法,格式: [public] default 返回值类型 方法名称(参数列表) { 方法体 }注意
:默认方法也可以被覆盖重写
从Java 8开始,接口里允许定义静态方法,格式: [public] static 返回值类型 方法名称(参数列表) { 方法体 }注意
:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法
从Java 9开始,接口里允许定义私有方法,格式: 普通私有方法:private 返回值类型 方法名称(参数列表) { 方法体 } 静态私有方法:private static 返回值类型 方法名称(参数列表) { 方法体 }注意
:private的方法只有接口自己才能调用,不能被实现类或别人使用。
==使用接口的时候,需要注意:==
接口是没有静态代码块或者构造方法的。
一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。 格式: public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { // 覆盖重写所有抽象方法 }
如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
如果实现类锁实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。```
狂神java Demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.oop.demo09;public class UserServiceImpl implements UserService ,TimeService { @Override public void run (String name) { } @Override public void delete (String name) { } @Override public void update (String name) { } @Override public void query (String name) { } @Override public void timer () { } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.oop.demo09;public interface UserService { void run (String name) ; void delete (String name) ; void update (String name) ; void query (String name) ; }
多态
代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
格式:
或者:
或者: 接口名称 对象名 = new 实现类名称();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package cn.itcast.day10.demo04;public class Demo01Multi { public static void main (String[] args) { Fu obj = new Zi(); obj.method(); obj.methodFu(); } } package cn.itcast.day10.demo04;public class Fu { public void method () { System.out.println("父类方法" ); } public void methodFu () { System.out.println("父类特有方法" ); } } package cn.itcast.day10.demo04;public class Zi extends Fu { @Override public void method () { System.out.println("子类方法" ); } }
访问成员变量
: 两种方式
直接通过对象名称访问成员变量:看等号左边
是谁,优先用谁,没有则向上找。
间接通过成员方法访问成员变量:看该方法属于谁
,优先用谁,没有则向上找。
成员变量不可以修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package cn.itcast.day10.demo05;public class Demo01MultiField { public static void main (String[] args) { Fu obj = new Zi(); System.out.println(obj.num); System.out.println("=============" ); obj.showNum(); } } package cn.itcast.day10.demo05;public class Fu /*extends Object */ { int num = 10 ; public void showNum () { System.out.println(num); } public void method () { System.out.println("父类方法" ); } public void methodFu () { System.out.println("父类特有方法" ); } } package cn.itcast.day10.demo05;public class Zi extends Fu { int num = 20 ; int age = 16 ; @Override public void showNum () { System.out.println(num); } @Override public void method () { System.out.println("子类方法" ); } public void methodZi () { System.out.println("子类特有方法" ); } }
成员方法
的访问规则在多态的代码当中,成员方法的访问规则是: 看new的是谁,就优先用谁,没有则向上找。
口诀:编译看左边,运行看右边。
编译:编译通过代码就不会出现红线;不通过IDE会出现红色的字
对比一下: 成员变量:编译看左边,运行还看左边。 成员方法:编译看左边,运行看右边。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package cn.itcast.day10.demo05;public class Demo02MultiMethod { public static void main (String[] args) { Fu obj = new Zi(); obj.method(); obj.methodFu(); } }
使用多态的好处
向上转型 & 向下转型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package cn.itcast.day10.demo06;public class Demo01Main { public static void main (String[] args) { Animal animal = new Cat(); animal.eat(); Cat cat = (Cat) animal; cat.catchMouse(); Dog dog = (Dog) animal; } } package cn.itcast.day10.demo06;public abstract class Animal { public abstract void eat () ; } package cn.itcast.day10.demo06;public class Cat extends Animal { @Override public void eat () { System.out.println("猫吃鱼" ); } public void catchMouse () { System.out.println("猫抓老鼠" ); } }
对应的向下转型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package cn.itcast.day10.demo06;public class Demo02Instanceof { public static void main (String[] args) { Animal animal = new Dog(); animal.eat(); if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.watchHouse(); } if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.catchMouse(); } giveMeAPet(new Dog()); } public static void giveMeAPet (Animal animal) { if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.watchHouse(); } if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.catchMouse(); } } }
狂神说java部分笔记
动态编译:类型:可扩展性更强
统一方法可以根据发送对象的不同而采取不同的行为方式
一个对象的实际类型是确定的,但可以指向对象的引用类型有很多(父类,有关系的类)
多态存在的条件
有继承的关系
子类重写父类方法
父类引用指向子类的对象
注意事项 :
多态是方法的多态,属性没有多态
父类和子类,有联系 类型转换异常!ClassCastException
存在的条件:继承关系,方法需要重写,父类的引用指向子类对象
static 方法,属于累,它不属于实例
final 常量
private 方法
instanceof (类型转换) 引用类型,判断一个对象是什么类型
父类引用指向子类的对象
把子类转换为父类,向上转型;可以直接转过去
把父类转换为子类,向下转型,强制转换
方便方法的调用,减少重复的代码!简洁
:抽象:封装,继承,多态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.oop.demo06;public class Application { public static void main (String[] args) { Student s1 = new Student(); Person s2 = new Student(); Object s3 = new Student(); s2.run(); ((Student)s2).eat(); s1.run(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.oop.demo06;public class Application { public static void main (String[] args) { System.out.println("=================================" ); Object object = new Student(); System.out.println(object instanceof Student); System.out.println(object instanceof Person); System.out.println(object instanceof Object); System.out.println(object instanceof Teacher); System.out.println(object instanceof String); System.out.println("=================================" ); Person person = new Student(); System.out.println(person instanceof Student); System.out.println(person instanceof Object); System.out.println(person instanceof Teacher); System.out.println("=================================" ); Student student = new Student(); System.out.println(student instanceof Student); System.out.println(student instanceof Object); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.oop.demo06;public class Application { public static void main (String[] args) { Person obj = new Student(); Student student = (Student) obj; student.go(); ((Student)obj).go(); } }
接口多态的综合案例 案例分析
https://github.com/yuxuanwu17/USB_demo
修饰符 在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,
1 2 3 4 5 6 7 8 public:公共的。 protected:受保护的 default:默认的 private:私有的
Java中有四种权限修饰符: public > protected > (default) > private
public
protected
(default)
private
同一个类(我自己)
YES
YES
YES
YES
同一个包(我邻居)
YES
YES
YES
NO
不同包子类(我儿子)
YES
YES
NO
NO
不同包非子类(陌生人)
YES
NO
NO
NO
注意事项
:(default)并不是关键字“default”,而是根本不写。
内部类 什么是内部类 将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
成员内部类
:定义在类中方法外的类。
定义格式:
1 2 3 4 5 6 7 class 外部类 { class 内部类 { } }
【外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();】
代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 package cn.itcast.day11.demo03;public class Demo01InnerClass { public static void main (String[] args) { Body body = new Body(); body.methodBody(); System.out.println("=====================" ); Body.Heart heart = new Body().new Heart () ; heart.beat(); } } package cn.itcast.day11.demo03;public class Body { public class Heart { public void beat () { System.out.println("心脏跳动:蹦蹦蹦!" ); System.out.println("我叫:" + name); } } private String name; public void methodBody () { System.out.println("外部类的方法" ); new Heart().beat(); } public String getName () { return name; } public void setName (String name) { this .name = name; } } package cn.itcast.day11.demo03;public class Outer { int num = 10 ; public class Inner /*extends Object */ { int num = 20 ; public void methodInner () { int num = 30 ; System.out.println(num); System.out.println(this .num); System.out.println(Outer.this .num); } } }
局部内部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package cn.itcast.day11.demo04;public class MyOuter { public void methodOuter () { int num = 10 ; class MyInner { public void methodInner () { System.out.println(num); } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package cn.itcast.day11.demo04;class Outer { public void methodOuter () { class Inner { int num = 10 ; public void methodInner () { System.out.println(num); } } Inner inner = new Inner(); inner.methodInner(); } }
局部内部类的final问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package cn.itcast.day11.demo04;public class MyOuter { public void methodOuter () { int num = 10 ; class MyInner { public void methodInner () { System.out.println(num); } } } }
匿名类部类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 package cn.itcast.day11.demo05;public class DemoMain { public static void main (String[] args) { MyInterface objA = new MyInterface() { @Override public void method1 () { System.out.println("匿名内部类实现了方法!111-A" ); } @Override public void method2 () { System.out.println("匿名内部类实现了方法!222-A" ); } }; objA.method1(); objA.method2(); System.out.println("=================" ); new MyInterface() { @Override public void method1 () { System.out.println("匿名内部类实现了方法!111-B" ); } @Override public void method2 () { System.out.println("匿名内部类实现了方法!222-B" ); } }.method1(); new MyInterface() { @Override public void method1 () { System.out.println("匿名内部类实现了方法!111-B" ); } @Override public void method2 () { System.out.println("匿名内部类实现了方法!222-B" ); } }.method2(); } } package cn.itcast.day11.demo05;public interface MyInterface { void method1 () ; void method2 () ; } package cn.itcast.day11.demo05;public class MyInterfaceImpl implements MyInterface { @Override public void method1 () { System.out.println("实现类覆盖重写了方法!111" ); } @Override public void method2 () { System.out.println("实现类覆盖重写了方法!222" ); } }
接口作为变量传递 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 package cn.itcast.day11.demo07;public class Hero { private String name; private Skill skill; public Hero () { } public Hero (String name, Skill skill) { this .name = name; this .skill = skill; } public void attack () { System.out.println("我叫" + name + ",开始施放技能:" ); skill.use(); System.out.println("施放技能完成。" ); } public String getName () { return name; } public void setName (String name) { this .name = name; } public Skill getSkill () { return skill; } public void setSkill (Skill skill) { this .skill = skill; } } package cn.itcast.day11.demo07;public interface Skill { void use () ; } package cn.itcast.day11.demo07;public class SkillImpl implements Skill { @Override public void use () { System.out.println("Biu~biu~biu~" ); } } package cn.itcast.day11.demo07;import java.util.ArrayList;import java.util.List;public class DemoInterface { public static void main (String[] args) { List<String> list = new ArrayList<>(); List<String> result = addNames(list); for (int i = 0 ; i < result.size(); i++) { System.out.println(result.get(i)); } } public static List<String> addNames (List<String> list) { list.add("迪丽热巴" ); list.add("古力娜扎" ); list.add("玛尔扎哈" ); list.add("沙扬娜拉" ); return list; } } package cn.itcast.day11.demo07;public class DemoGame { public static void main (String[] args) { Hero hero = new Hero(); hero.setName("艾希" ); hero.setSkill(new Skill() { @Override public void use () { System.out.println("Biu~Pia~Biu~Pia~" ); } }); hero.attack(); } }
抢红包实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package cn.itcast.day11.demo08; import cn.itcast.day11.red.OpenMode; /* 场景说明: 红包发出去之后,所有人都有红包,大家抢完了之后,最后一个红包给群主自己。 大多数代码都是现成的,我们需要做的就是填空题。 我们自己要做的事情有: 1. 设置一下程序的标题,通过构造方法的字符串参数 2. 设置群主名称 3. 设置分发策略:平均,还是随机? 红包分发的策略: 1. 普通红包(平均):totalMoney / totalCount,余数放在最后一个红包当中。 2. 手气红包(随机):最少1分钱,最多不超过平均数的2倍。应该越发越少。 */ public class Bootstrap { public static void main(String[] args) { MyRed red = new MyRed("传智播客双元课程"); // 设置群主名称 red.setOwnerName("王思聪"); // 普通红包 // OpenMode normal = new NormalMode(); // red.setOpenWay(normal); // 手气红包 OpenMode random = new RandomMode(); red.setOpenWay(random); } }
狂神说java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.oop.demo10;public class Outer { private int id=10 ; public void out () { System.out.println("这是外部类的方法" ); } public class Inner { public void in () { System.out.println("这是内部类的方法" ); } public void getID () { System.out.println(id); } } }
1 2 3 4 5 6 7 8 9 10 11 package com.oop.demo10;public class Application { public static void main (String[] args) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner () ; inner.in(); } }
一个java类中可以有多个class类,但是只能有一个public class
异常处理
异常的处理机制 抛出/捕获异常
Idea 快捷键 option+command+T
主动跑出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.exception;import com.oop.demo07.Test;public class Test2 { public static void main (String[] args) { new Test2().test(1 , 0 ); } public void test (int a ,int b) { if (b == 0 ) { throw new ArithmeticException(); } } }
java protected关键字: 同包不同级
基类的 protected 成员是包内可见的,并且对子类可见;
若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法