Java SE
数据类型
-
整数拓展 : 进制 二进制0b 十进制 八进制0 十六进制0x
int i = 10; int i2 = 010//八进制0 int i3 = 0x10//十六进制0x 0~9 A~F 16
-
浮点数拓展? 银行业务怎么表示? 钱
BigDecimal 数学工具类
float: 有限 离散 舍入误差 大约 接近但不等于
double
最好避免使用浮点数进行比较
float f = 0.1f; //0.1 double d = 1.0/10; //0.1 System.out.println(f==d); //结果为false float d1 = 23213131231231313f; float d2 = d1 + 1; System.out.println(d1==d2); //结果为true
-
字符拓展?
char c1 = 'A' char c2 = '中' //强制转换 System.out.println(int(c1)); //结果: 65 Unicode表 System.out.println(int(c2)); //结果: 20013 char c3 = '\u0061'; //结果: a (/u指转义) //转义字符 // \t 制表符 // \n 换行 // ... System.out.println("Hello\tWorld"); // Hello World
类型转换
-
低 ---------------------------------------------------- 高
byte,short ,char-> int-> long-> float-> double
强制转换 高–低 (类型)变量名
自动转换 低–高
int i = 128; byte b = (byte)i; //内存溢出 byte范围: -128 ~ 127 System.out.println(i); //128 System.out.println(b); //-128 double b = i;//128.0 /* 注意点: 1. 不能对布尔值进行转换 2. 不能把对象类型转换为不相干的类型 3. 在把高容量转换到低容量的时候, 强制转换 4. 转换的时候可能存在内存溢出 ,或精度问题 */ System.out.println((int)23.7); //23 System.out.println((int)-45.89f); //-45 char c = 'a'; int d = c + 1; System.out.println(d); // 98 System.out.println((char)d); // b
-
注意点
//操作比较大的数的时候 ,注意溢出问题 //JDK7 新特性 , 数字之间可以使用下划线分割 int money = 10_0000_0000; int years = 20; int total = money*years; //-1474836480 , 计算的时候溢出了 long total2 = money*years; //默认是int , 转换之前已经存在问题了 int total3 = money*((long)years); //20000000000 (此时在计算的时候就转了)
变量、常量、作用域
-
//变量 成员变量(全局变量) = 静态变量 + 实例变量 public class Demo01(){ //类变量 static (静态变量) //类变量随着类的加载而存在于==方法区==中。 /* 静态变量(类变量)具备以下特点: 随着类的加载而加载 优先于对象存在 被所有对象所共享 可以直接被类名调用 */ /* 类变量的默认初始化: (是类变量则会默认初始化,局部变量不会) 数字: 0 0.0 char : u0000 boolean : false 引用 : null */ static double salary = 2500; //实例变量: 从属于对象; 如果不进行初始化,这个类型的默认值 0 0.0 //实例变量随着对象的建立而存在于==堆内存==中 //布尔值: 默认是false //除了基本类型 , 其余默认值都是null; String name; int age; int sameName; public static void main(String[] args){ //局部变量: 必须声明和初始化值 int i = 10; System.out.println(i); //类变量 static System.out.println(salary); new 哈哈哈哈哈哈().test01(10);//局部变量的: 10 new 哈哈哈哈哈哈().test02(); //成员变量的: 0 } //局部变量和成员变量重名的时候,在方法内的局部变量会覆盖掉成员变量 public void test01(int sameName){ sameName = sameName;//这里的sameName与成员变量中的sameName毫无关系 System.out.println("局部变量的: "+sameName); } public void test02(){ System.out.println("成员变量的: "+sameName); } //运行结果见main方法里的注释 }
-
//常量 public class Demo02 { //修饰符,不区分先后顺序 static final double PI = 3.14; public static void main(String[] args) { System.out.println(PI); } }
-
变量的命名规范
- 所有变量、方法、类名:见名起意
- 类成员变量: 首字母小写和驼峰原则: monthSalary 除了第一个单词以外 , 后面的单词首字母大写 lastName
- 局部变量: 首字母小写和驼峰原则
- 常量:大写字母和下划线: MAX_VALUE
- 类名: 首字母大写和驼峰原则: Man, GoodMan
- 方法名: 首字母小写和驼峰原则: run(), runMan()
逻辑运算符,位运算符
-
//逻辑运算符 public class Demo03 { public static void main(String[] args) { //短路运算 int c = 5; boolean d = (c<4)&&(c++<4); //进行&&运算时,执行了c<4后就已经判断是错的了,所以后面不执行 System.out.println(d); // false System.out.println(c); // 5 } }
-
//位运算符 public class Demo04 { public static void main(String[] args) { /* A = 0011 1100 B = 0000 1101 ------------------------------------------- A&B = 0000 1100 (同为1就得到1,否则为0) A|B = 0011 1101 (有1就得到1,无则为0) A^B = 1100 1110 (相同则为0,否则为1) ~B = 1111 0010 2 * 8 = 16 2*2*2*2 << *2 >> /2 0000 0000 0 0000 0010 2 0000 0100 4 0000 1000 8 0001 0000 16 */ System.out.println(2<<3); }
-
//字符串连接符 public class Demo05 { public static void main(String[] args) { int a = 10; int b =20; //字符串连接符 + , String +号的两边有“”则会将它拼接成字符串 System.out.println(""+a+b); // 1020 System.out.println(a+b+""); // 30 这里是先进行的加法(此时两边都是int类型),再进行的拼接 } }
-
三元运算符
x ? y : z
如果x==true, 则结果为y,否则结果为z
包机制
- 一般利用公司域名倒置 e.g. com.baidu.www
- 导入包 import java.util.Data; (注: import一定要在package下面)
- 通配符 * 会导入这个包下所有的类
JavaDoc生成文档
-
javadoc 参数信息 java文件
一般形式 javadoc -encoding UTF-8 -charset UTF-8 java文件
-
javac : 编译java文件
-
@Since : 指明需要最早使用的jdk版本
/** * @author ZCH * @date 2020/9/13 0013 - 下午 4:14 * @version 1.0 * @since 1.8 */ public class Doc { String name; /** * * @param name * @return */ public String test(String name){ return name; } }
用户交互Scanner
-
public class Demo06 { public static void main(String[] args) { //创建一个扫描器对象 , 用于接收键盘数据 Scanner scanner = new Scanner(System.in); System.out.println("使用next方式接收:"); //判断用户有没有输入字符串 if (scanner.hasNext()){ //使用next方式接收 String str = scanner.next(); //程序会等待用户输入完毕 System.out.println("输出的内容为: "+str); //输出的内容为: hello } //凡是属于IO流的类如果不关闭会一致占用资源,要养成好习惯用完就关闭 scanner.close(); } } public class Demo07 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); System.out.println("输出的内容为: "+str); //输出的内容为: Hello World scanner.close(); } } /* next(): 1.next()不能得到带有空格的字符串 2.在输入有效字符后会将其后面输入的空白作为分隔符或者结束符。 3.对输入有效字符之前遇到的空白, next()方法会自动将其去掉。 4.一定要读取到有效字符后才能结束 5.!!! 使用了scanner.next();后就不能再在控制台进行输入操作了,程序会直接结束 !!!! nextLine(): 1.nextLine() 以Enter作为结束符,也就是说nextLine()方法返回的是输入回车前的所有字符 */
-
public class Demo08 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); //和 double sum = 0; //计算输入了多少数字 int m = 0; System.out.println("请输入任意个数,不是数的时候会结束"); //通过循环判断是否还有输入 , 并在里面对每一次进行求和和统计 while (scanner.hasNextDouble()){ // 只要输入的数是double类型的,就能一直输入下去 double x = scanner.nextDouble(); m++; sum+=x; } System.out.println(m + "个数的和为"+ sum); System.out.println(m + "个数的平均值为"+ (sum/m)); } }
Switch多选择结构
-
switch语句中的变量类型可以是:
- byte 、 short 、 int 或者是 char
- 从 Java SE 7 开始 switch支持字符串 String 类型了
- 同时case标签(指后面跟一个冒号的标识符)必须为字符串常量或字面量。
switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 ... default : //可选 //语句 }
循环
-
public class Demo10 { public static void main(String[] args) { //练习: 打印一个三角形(五行1,3,5,7,9) int len = 5; for (int i = 1; i <= len; i++) { for (int j = 1; j <= len - i; j++) { System.out.print(" "); } for (int j1 = 1; j1 <= (2 * i - 1); j1++) { System.out.print("*"); } System.out.println(); } } } * *** ***** ******* *********
命令行传递参数
有时候你希望运行一个程序时再给它传递消息。 这要靠传递命令行参数给main()函数实现
-
public class Demo11 { public static void main(String[] args) { for (int i = 0; i< args.length; i++){ System.out.println("args["+ i +"]"+args[i]); } } }
可变参数
-
JDK1.5开始 , Java支持传递同类型的可变参数给一个方法
-
在方法声明中, 在指定参数类型后加一个省略号(…)。
-
一个方法只能指定一个可变参数, 它必须是方法的最后一个参数。 任何普通的参数必须在它之前声明。
public class Demo13 { public static void main(String[] args) { //调用可变参数的方法 printMax(34,21,23,123,4,13); printMax(new double[]{21,32,43}); } public static void printMax(double... numbers){ if (numbers.length ==0){ System.out.println("No arguement 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); } }
递归
-
递归头: 什么时候不调用自身方法。 如果没有头 , 将陷入死循环。
递归体: 什么时候需要调用自身方法。
2.练习:
数组
-
三种初始化
//1.静态初始化 : 创建+赋值 int[] a = {1,2,3}; Man[] mans = {new Man(),new Man()}; //2. 动态初始化 : 包含默认初始化 int[] a = new int[2]; a[0] = 1; a[1] = 2; //数组的默认初始化 //数组是引用类型 , 它的元素相当于类的实例变量 , 因此数组一经分配空间, 其中的每个元素也被按照实例变量同样的方式被隐式初始化
-
数组的四个基本特点
-
其长度是确定的,数组一旦被创建, 它的大小就是不可改变的。
-
其元素必须是相同类型,不允许出现混合类型。
-
数组中的元素可以是任何数据类型,包括基本类型和引用类型。
-
数组变量属于引用类型,数组也可以看作是对象, 数组中的每个元素相当于该对象的成员变量。
数组本身就是对象, Java中对象是在堆中的, 因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
-
-
数组边界
-
合法区间: 【0,length-1】
-
数组下标越界异常: ArrayIndexOutOfBoundsException
-
-
数组使用
int[] arrays = {1,2,3,4,5}; for(int array : arrays){ System.out.println(array); } //for-each(增强for循环)
-
稀疏数组
-
当一个数组中大部分元素为0, 或者为同一值的数组时, 可以使用稀疏数组来保存该数组。
-
稀疏数组的处理方式是:
- 记录数组一共有几行几列, 有多少个不同值
- 把具有不同值的元素和行列及值记录在一个小规模的数组中, 从而缩小程序的规模
-
public class Demo17 { public static void main(String[] args) { //1.创建一个二维数组 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(); } //转换为稀疏数组 //获得有效值的个数 int count = 0; for (int i = 0; i < array1.length; i++) { for (int j = 0; j < array1[0].length; j++) { if (array1[i][j] != 0){ count++; } } } System.out.println("有效值个数: "+ count); int[][] array2 = new int[count+1][3]; array2[0][0] = array1.length; array2[0][1] = array1[0].length; array2[0][2] = count; count = 0; for (int i = 0; i < array1.length; i++) { for (int j = 0; j < array1[0].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("稀疏数组为:"); for (int[] ints : array2) { for (int anInt : ints) { System.out.print(anInt+"\t"); } System.out.println(); } System.out.println("==========================================="); System.out.println("还原"); //1.读取稀疏数组, 创建还原后的数组 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]; } System.out.println("还原后的数组为: "); for (int[] ints : array3) { for (int anInt : ints) { System.out.print(anInt+"\t"); } System.out.println(); } } } 输出原始的数组 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 有效值个数: 2 稀疏数组为: 11 11 2 1 2 1 2 3 2 =========================================== 还原 还原后的数组为: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Process finished with exit code 0
-
Arrays类
-
public class Demo15 { public static void main(String[] args) { int[] a = {12,12,21,42,15,44,32}; System.out.println(a); //[I@1540e19d System.out.println(Arrays.toString(a)); // [12, 12, 21, 42, 15, 44, 32] Arrays.sort(a); //对数组进行排序 ;升序 System.out.println(Arrays.toString(a)); Arrays.fill(a,2,4,0); //将val分配给数组里每一个元素(若指定了fromIndex和toIndex就是制定范围内填充) System.out.println(Arrays.toString(a)); } }
排序
-
public class Demo16 { public static void main(String[] args) { int[] array = {32,21,12,11,2,1,45,32}; sort(array); System.out.println(Arrays.toString(array)); } //冒泡排序(降序) 改动大于号即可变为升序 private static void sort(int[] a) { for (int turn = 0;turn < a.length-1; turn++){ for (int j = 1; j<=a.length-1-turn; j++ ) if (a[j]>a[j-1]){ int tmp = a[j]; a[j] = a[j-1]; a[j-1] = tmp; } } } }
方法的调用
-
public class Demo18 { public static void main(String[] args) { Student.hello(); //调用其他类的静态方法,可以用类名.xxx的形式 } // 因为static修饰的变量或方法是随着类一汽加载的 public static void One(){ // Two(); // 这样会报错 } public static void One1(){ One(); //一个类中,同为静态方法可以直接调用 } // 类实例化之后 才存在的 public void Two(){ One(); // 这里应该是因为在同一个类里,所以可以直接调用。 } } public class Student { public static void hello(){ } }
-
值传递:
引用传递:
类与对象的关系
-
类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一事物。
-
对象是抽象概念的具体实例,类是对象的模板
-
面向对象(Object-Oriented Programming,OOP)的本质: 以类的方式组织代码, 以对象的方式组织(封装)数据。
-
创建与初始化对象
-
使用new关键字创建对象
使用new关键字创建对象的时候, 除了分配内存空间以外, 还会给创建好的对象 进行默认的初始化以及 对类中构造器的调用。
-
类中的构造器也称作构造方法, 是在进行创建对象的时候必须要调用的。 并且构造器有以下两个特点:
- 必须和类的名字相同
- 必须没有返回类型,也不能写void
- 构造函数里的this是与对象绑定的(我猜的)
-
封装
- 该露的露,该藏的藏
- 程序设计追求“高内聚,低耦合”。 高内聚: 类的内部数据操作细节自己完成, 不允许外部干涉; 低耦合: 仅暴露少量的方法给外部使用。
- 封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示, 而应通过操作接口来访问, 这称为信息隐藏。
- 记住一句话: 属性私有, get/set
继承
-
子类和父类之间的关系
- 继承的本质是对某一批类的抽象, 从而实现对现实世界更好的建模。
- extends的意思是 “扩展” 。 子类是父类的扩展。
- Java中类只有单继承, 没有多继承!
- 继承是类和类之间的一种关系。 除此之外, 类和类之间的关系还有依赖,组合,聚合等。
- 继承父类的两个类, 一个为子类(派生类), 一个为父类(基类)。 子类继承父类,使用关键字extends来表示。
- 子类和父类之间, 从意义上说应该有“is a”关系
- 子类继承了父类, 就会拥有父类的全部方法(不能是private修饰的方法和属性)public>protected>default>private
- 所有的类, 都默认直接或间接继承了Object类
- 创建子类对象的时候,会先调用父类的构造方法
-
public class Student extends Person{ private String name = "hahaha"; public void print(){ System.out.println(name); //hahaha (如果子类和父类都有同一属性,默认情况下是子类的) System.out.println(this.name); //hahaha System.out.println(super.name); //hahaha } } public class Person { protected String name = "zhuge"; }
-
Super注意点:
- super调用父类的构造方法, 必须在构造方法的第一个
- super 必须只能出现在子类的方法或者构造方法中!
- super 和 this 不能同时调用构造方法!
-
this 与 Super的不同之处:
-
this: 代表的对象是本身调用者这个对象
super: 代表父类对象的应用
-
this: 没有继承也可以使用
super: 只能在继承条件才可以使用
-
this(): 本类的构造
super(): 父类的构造
-
-
方法的重写(都是方法的重写,和属性无关)
-
public class Application { //静态的方法和非静态的方法区别很大! //静态方法: //方法的调用只和左边, 定义的数据类型有关 public static void main(String[] args) { Student a = new Student(); a.test();//Student=>test() //父类的引用指向了子类 Person b = new Student(); b.test();//Person=>test() } } public class Student extends Person{ public static void test(){ System.out.println("Student=>test()"); } } public class Person { public static void test(){ System.out.println("Person=>test()"); } }
-
public class Application { //此时两个类里不是static修饰的方法了,所以子类会重写父类里的test() public static void main(String[] args) { Student a = new Student(); a.test();//Student=>test() //父类的引用指向了子类 Person b = new Student(); b.test();//Student=>test() } } public class Person { public void test(){ System.out.println("Person=>test()"); } } public class Student extends Person{ @Override public void test(){ System.out.println("Student=>test()"); } }
-
重写的总结: 必须要有继承关系, 子类重写父类的方法!
- 方法名必须相同
- 参数列表必须相同
- 修饰符: 范围可以扩大但不能缩小;
- 抛出的异常: 范围,可以被缩小, 但不能扩大
- 重写, 子类的方法和父类必须要一致: 方法体不同!
-
多态
-
public class Application { public static void main(String[] args) { //一个对象的实际类型是确定的 //new Student() //new Person() //可以指向的引用类型就不确定了: 父类的引用指向子类 //Student 能调用的方法都是自己的或者继承父类的! Student s1 = new Student(); //Person 父类型, 可以指向子类, 但是不能调用子类独有的方法(即父类里没定义的方法) Person s2 = new Student(); Object s3 = new Student(); //对象能执行哪些方法, 主要看对象左边的类型, 和右边的关系不大! //s2.eat();//这样写是会报错的 s2.run(); //子类重写了父类的方法, 执行子类的方法 s1.eat();// eat, Student } } public class Person { public void run(){ System.out.println("run, Person"); } } public class Student extends Person{ public void run(){ System.out.println("run, Student"); } public void eat(){ System.out.println("eat, Student"); } }
-
多态注意点
-
多态是方法的多态, 属性没有多态
-
父类和子类, 有联系, 类型转换异常! ClassCastException!
-
存在条件: 继承关系, 方法需要重写, 父类引用指向子类对象! Father f1 = new Son();
- static 方法, 属于类, 它不属于实例(以下三个没法重写)
- final 常量
- private 方法
-
同一方法可以根据发送对象的不同而采用多种不同的方式。(子类重写了之后就是一样的了)
-
一个对象的实际类型是确定的, 但可以指向对象的引用的类型有很多(父类, 有关系的类)
-
-
instanceof (类型转换) 引用类型, 判断一个对象是什么类型~
System.out.println(X instanceof Y ) //1.能不能编译通过 2. X所指向的对象与Y所指向的对象有没有关系
public class Application { public static void main(String[] args) { //Object > String //Object > Person > Teacher //Object > Person > Student Object object = new Student(); System.out.println(object instanceof Student);//true System.out.println(object instanceof Person);//true System.out.println(object instanceof Object);//true System.out.println(object instanceof teacher);//false System.out.println(object instanceof String);//false System.out.println("======================================"); Person person = new Student(); System.out.println(person instanceof Student);//true System.out.println(person instanceof Person);//true System.out.println(person instanceof Object);//true System.out.println(person instanceof teacher);//false // System.out.println(person instanceof String);//编译时就会报错, 因为Person 跟 String 压根没有半毛线关系 System.out.println("======================================"); Student student = new Student(); System.out.println(student instanceof Student);//true System.out.println(student instanceof Person);//true System.out.println(student instanceof Object);//true //System.out.println(student instanceof teacher);//编译时就会报错 //System.out.println(student instanceof String);//编译时就会报错 } } public class Person { public void run(){ System.out.println("run, Student"); } public void eat(){ System.out.println("eat, Student"); } } public class teacher extends Person{ } public class Student extends Person{ }
-
引用类型之间的转换
-
public class Application { public static void main(String[] args) { //类型之间的转化: 父 子 //高 低 Person obj = new Student(); //(Student)将这个对象转换为Student类型, 我们就可以使用Student类型的方法了。 ((Student) obj).go(); //子类转化为父类, 可能丢失自己的本来的一些方法 Student student = new Student(); Person person = student; //person.go();//此时就不能调用子类里的方法了。 } } public class Person { public void run(){ System.out.println("run, Student"); } public void eat(){ System.out.println("eat, Student"); } } public class teacher extends Person{ } public class Student extends Person{ public void go(){ System.out.println("go"); } }
-
引用类型中转换总结:(与基本类型之间的转换类似)
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型;
- 把父类转换为子类, 向下转型: 强制转换
- 方便方法的调用, 减少重复的代码!
-
Static
-
一部分见方法的调用模块
-
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(); System.out.println("=========="); Person person1 = new Person(); } } 静态代码块 匿名代码块 构造方法 ========== 匿名代码块 构造方法 //static代码块只能执行一次
-
package demo; import static java.lang.Math.random; public class Demo19 { public static void main(String[] args) { System.out.println(random());// 生成随机数: 0.9789288397718761 } } //import static xxx 静态导入包,就不用写Math.random了
抽象类
-
//abstract 抽象类(没有构造方法): 类 extends: 单继承~ (接口可以多继承) public abstract class Action { //abstract , 抽象方法, 只有方法名字, 没有方法的实现! public abstract void doSomething(); //如果不是abstract类型的方法,则必须有方法体,且不是abstract类型的方法子类可以不用实现。 public void haha() { } //1. 不能new这个抽象类, 只能靠子类去实现它: 约束! //2. 抽象类中可以写普通的方法~ //3. 抽象方法必须在抽象类中~ //抽象的抽象: 约束~ //存在的意义: 抽象出来~ 提高开发效率 } public class A extends Action{ //必须实现抽象类中的抽象方法(用abstract修饰的方法) @Override public void doSomething() { System.out.println("hehe"); } }
接口
-
public interface UserService { //接口中的所有定义其实都是抽象的 public abstract //接口中的所有属性其实都是静态的 public static //常量~ int AGE = 99; public static int age = 100; void add(); public abstract void delete(); }
-
接口总结
- 约束
- 定义一些方法, 让不同的人实现~
- public abstract
- public static
- 接口不能实例化,没有构造方法
- implements可以实现多个接口
- 必须要重写接口中的方法。
- 如果在接口里定义static方法,则必须有方法体,且实现该接口的类不用实现此方法
内部类
-
成员内部类
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); } } } public class Application { public static void main(String[] args) { Outer outer = new Outer(); //通过这个外部类来实例化内部类 Outer.Inner inner = outer.new Inner(); inner.getId(); } }
-
静态内部类
public class Outer { private int id = 10; public void out(){ System.out.println("这是外部类的方法"); } public static class Inner{ public void in(){ System.out.println("这是静态内部类的方法"); } //此时,Inner就不能访问外部类的私有成员了,因为静态类是先加载的(之间写过笔记) // //获得外部类的私有属性~ // public void getId(){ // System.out.println(id); // } } }
-
public class Outer { private int id = 10; public void out(){ System.out.println("这是外部类的方法"); } } //一个java类中可以有多个class类, 但是只能有一个public class 类 class AB{ public static void main(String[] args) { } }
-
局部内部类
public class Outer { //局部内部类 public void method(){ class Inner{ public void in(){ } } } }
-
匿名内部类
public class Application { public static void main(String[] args) { //没有名字初始化类,不用将实例保存到变量中~ (其实new其他类也可以这样) new Apple().eat(); new UserService1(){ @Override public void hello() { } }; } } class Apple{ public void eat(){ System.out.println("1"); } } interface UserService1{ void hello(); }
异常
-
Java 把异常当做对象来处理, 并定义一个基类java.lang.Throwable作为所有异常的超类。
-
在Java API 中已经定义了许多异常类, 这些异常类分为两大类, 错误Error和异常Exception
-
Error
- Error类对象由 Java 虚拟机生成抛出, 大多数错误与代码编写者所执行的操作无关。
- Java虚拟机运行时错误(Virtual MachineError), 当JVM不再有继续执行操作所需的内存资源时, 将出现 OutOfMemoryError。 这些异常发生时, Java虚拟机(JVM)一般会选择线程中止。
- 还有发生在虚拟机试图执行应用时, 如类定义错误 (NoClassDefFoundError)、 链接错误(LinkageError)。这些错误是不可查的, 因为他们在应用程序的控制和处理能力之外, 而且绝大部分是程序运行时不允许出现的错误。
-
Exception
- 在Exception分支里有一个重要的子类RuntimeException (运行时异常),如数组越界,空指针,算术, 丢失资源, 找不到类等异常, 这些异常是不检查异常, 程序中可以选择捕获处理, 也可以不处理。
- 这些异常一般是由程序逻辑错误引起的, 程序应该从逻辑角度尽可能避免这类异常的发生
-
Error和Exception的区别:
- Error通常是灾难性的致命的错误, 是程序无法控制和处理的, 当出现在这些异常时, Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的, 并且在程序中应尽可能地去处理这些异常。
-
捕获和处理异常
用try-catch处理后,即便出现了错误也程序也不会停止,若没有捕获处理则会终止。
-
自定义的异常类
//自定义的异常类 public class MyException extends Exception{ //传递数字>10 private int detail; public MyException(int a){ this.detail = a; } //异常的打印信息 @Override public String toString() { return "MyException{" + "detail=" + detail + '}'; } } public class test0 { //可能会存在异常的方法 static void test(int a) throws MyException { if (a>10){ if (a>10){ throw new MyException(a);// } } System.out.println("OK"); } public static void main(String[] args) { try { test(11); } catch (MyException e) { //增加一些处理异常的代码 System.out.println("MyException=>"+e); } } }
-
实际应用中的经验总结:
- 处理运行时异常时, 采用逻辑去合理规避同时辅助 try-catch处理
- 在多重catch块后面, 可以加一个catch(Exception)来处理可能会被遗漏的异常
- 尽量去处理异常,而不是简单地调用printStackTrace()去打印输出
- 具体如何处理异常, 要根据不同的业务需求和异常类型去决定
- 尽量添加finally语句块去释放占用的资源