Core Java学习笔记(八)--泛型
泛型基础
为什么引入泛型
- 装入数据的类型都被当作Object对待,从来丢失自己实际类型,获取数据时需要强制转型
- 将类型转换时的类型检查从运行时提前到了编译时,具有更好的可读性和安全性
- 代码可以被不同类型的对象重用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args) {
ArrayList arraylist = new ArrayList(); //定义ArrayList集合
//ArrayList<String> arraylist = new ArrayList<String>();
arraylist.add("11"); //存入字符串类型
arraylist.add("22");
//arraylist.add(33); 使用泛型编译期类型检查
for (int i = 0; i < arraylist.size(); i++) {
/*存入数据均作为Object看待,取出必须强制转换
33无法输出,Interger对象无法直接转换为String,需要调用toString方法
使用泛型则不需要强制转换 */
String name = (String) arraylist.get(i);
System.out.println("name:" + name);
}
}
}
泛型类:实例化类的时候指明泛型的具体类型
1
2泛型方法:调用方法的时候指明泛型的具体类型
- 泛型接口
泛型限定 extends super
泛型擦除
约束与局限性
泛型类型的继承规则
通配符
Core Java学习笔记(七)--Java常用类
包装类
- 为什么要有包装类?
- Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的
- 集合需要
自动装箱 & 自动拆箱(编译器)
- 自动装箱:基本类型自动转为包装类(int >> Integer)
- 自动拆箱:包装类自动转为基本类型(Integer >> int)
1
2
3
4
5
6
7public class TestInteger {
public static void main(String[] args) {
Integer i = new Integer(100); //Java5.0之前必须new生成一个Integer对象
Integer j = 100; //自动装箱,调用Integer.valueOf()方法实现,效率更高
int m = j; //自动拆箱,调用Integer.intValue()方法实现
}
}
缓存机制cache
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
35public class TestVlaueOf {
public static void main(String[] args) {
Integer i1 = 100; //Integer、Short、Byte、Character、Long类似
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2); //true
System.out.println(i3==i4); //false
System.out.println(i1.equals(i2)); //true
System.out.println(i3.equals(i4)); //true
/*通过valueOf方法创建Integer对象的时候,如果数值在 [-128,127] 之间,便返回指向
IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
*/
Double j1 = 100.0;
Double j2 = 100.0;
Double j3 = 200.0;
Double j4 = 200.0;
System.out.println(j1==j2); //false
System.out.println(j3==j4); //false
Boolean k1 = false;
Boolean k2 = false;
Boolean k3 = true;
Boolean k4 = true;
System.out.println(k1==k2); //true
System.out.println(k3==k4); //true
}
}
String
- String类简介
- String类常用方法
- String、StringBuilder & StringBuffer区别
日期处理:date。calendar
- Date
- Calendar
Math & Random
System
scanner
Core Java学习笔记(六)--异常
异常
异常概念
异常(exception)是运行期发生的事件,如果不对异常进行正确处理,可能导致程序的中断执行或外部环境影响造成用户数据丢失,所以在程序设计过程中必须考虑各种异常的发生,并正确处理,保证程序正确执行;- 运行期:指java.exe,即程序执行过程;javac.exe编译时不产生对象,只检查语法错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class ExceptionDemo01 {
public static void main(String[] args) {
int[] arr = {1,2,3};
System.out.println(2/0);
System.out.println(arr[3]);
}
}
/* javac编译不会报错,java执行期间报除数为0错误:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionDemo01.main(ExceptionDemo01.java:4)
此程序只报错以上一个错误,原因:如果发生异常不去处理(try,catch),程序运行
终止;
若执行System.out.println(arr[3]);发生数组下标越界错误:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at ExceptionDemo01.main(ExceptionDemo01.java:5) */
- 运行期:指java.exe,即程序执行过程;javac.exe编译时不产生对象,只检查语法错误
异常分类:
- Error:无法控制,罕见
- Exception:所有异常类的父类,其子类对应了各种各样可能出现的异常事件
- RuntimeException:
- 处理异常try catch finally
打印异常信息printstacktrace - 如何抛出异常 throw & throws
- 自定义异常:
断言
- 概念:
- 启用与禁用断言:
- 什么时候选择使用断言:
日志
Core Java学习笔记(四)--包、枚举 & 注解
Core Java学习笔记(五)--接口、Lambda表达式与内部类
接口
接口概念 好处是一种规范,不给实现 分离 定义
java单继承,通过继承可以实现多继承1
2
3
4
5
6
7
8//接口不是类,不能用new实例化一个接口 X = new Test; error
public interface Test {
//接口不能包含实例域,但可以定义常量,默认public static final,省略
int id = 10;
/*接口中的方法自动属于public,可省略关键字public
接口中的方法均为抽象方法,省略abstract */
void Method01();
}接口的实现 implements
- 一个类可以实现多个接口:Teacher类实现了Singer、Painter接口
- 多个无关的类可以实现同一个接口:Student类、Teacher类都实现了Singer接口
- 多态
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
47interface Painter { //Painter接口
void eat(); //两个抽象方法
void paint();
}
interface Singer { //Singer接口
void sing(); //两个抽象方法
void sleep();
}
class Student implements Singer {
public void sing() { //实现接口中的sing方法
System.out.println("Student is singing;");
}
public void sleep() { //实现接口中的sleep方法
System.out.println("Student is sleeping;");
}
}
class Teacher implements Singer,Painter {
public void eat() {
System.out.println("Teacher is eating;");
}
public void paint() {
System.out.println("Teacher is painting;");
}
public void sing() {
System.out.println("Teacher is singing;");
}
public void sleep() {
System.out.println("Teacher is sleeping;");
}
}
public class InterfaceTest {
public static void main(String[] args) {
Singer s1 = new Student();
s1.sing();
s1.sleep();
Singer s2 = new Teacher();
s2.sing();
s2.sleep();
Painter p1 = (Painter)s2;
p1.eat();
p1.paint();
}
}
画内存图
- 接口与抽象类
Lambda表达式
内部类
- 内部类:定义在另一个类中的类;为什么使用内部类?
- 内部类中的方法可以访问外部类的所有成员属性和方法,包括私有数据
- 内部类可以对同一个包中的其他类隐藏起来
- 当想要定义一个回调函数且不想编写代码时,使用匿名内部类更加便捷
成员内部类:最普通的内部类,与外部类的成员变量和方法并列,相当于外部类的一个成员,外部类要访问内部类的成员属性和方法则需要通过构造内部类实例来访问
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/*在编译时,编译器将内部类翻译成用$分隔外部类与内部类名的常规类文件(两个.class文件:
OuterClass.class、OuterClass$InnerClass),内部类的对象总有一个隐式引用,
它指向了创建它的外部类对象 */
public class OuterClass {
private String str; //外部类私有属性
public void outerInfo() {
System.out.println("outerClass");
}
public class InnerClass { //内部类
public void innerInfo() {
str = "Litsao"; //内部类直接调用外部类私有属性
System.out.println(str);
outerInfo(); //内部类直接调用外部类方法
}
}
public static void main(String[] args) {
//外部类实例化:外部类 对象1 = new 外部类();
OuterClass outer = new OuterClass();
/*成员内部类是依附于外部类的,所以只有先创建了外部类才能够创建内部类
*内部类实例化:外部类.内部类 对象2 = 对象1.new 内部类();
*/
OuterClass.InnerClass inner = outer.new InnerClass();
inner.innerInfo(); //构造内部类实例后才能访问内部类的成员变量/方法
}
}局部内部类:内部类定义在外部类的方法中,内部类的作用域只在方法内部
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
32public class LocalInnerClass {
public static void main(String[] args){
Outer outer = new Outer();
//外部类对象通过其方法调用内部类,方法结束局部内部类的对象也就释放了
outer.showOuter();
}
}
class Outer {
private int num1 = 10;
private static int num2 = 20;
public void showOuter(){
final int num3 = 50;
//局部内部类不是类成员,放在方法内部,前面不能有修饰符
class Inner {
private int num1 = 20;
private int num2 = 30;
public void showInner() {
System.out.println("内部类num1:" + num1); //20,打印内部类的num1、num2
System.out.println("内部类num2:" + num2); //30
//局部内部类访问外部类成员:外部类.this.成员
System.out.println("外部类num1" + Outer.this.num1); //10,打印外部类的num1
System.out.println("外部类静态变量:" + num2);
//局部内部类访问作用域内的局部变量,该局部变量需要使用final修饰
System.out.println("作用域内局部变量:" + num3);
}
}
//局部内部类的对象需在内部类编译后再创建
//局部内部类对于外界是隐藏的,因此需要在内部类里面完成对象的定义和引用
Inner inner=new Inner();
inner.showInner();
}
}匿名内部类:特殊的局部内部类,没有名字,只使用一次
1
2静态内部类:使用static修饰的内部类(嵌套内部类)
非静态内部类不能包含static成员?1
2
Core 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//此处仅封装了属性,同样可以利用private实现私有方法(后面介绍:封装构造方法<单例模式>)
class Employee {
private String name; //封装属性,只需要加上访问控制符private
private double salary;
public String getName() { //提供getter/setter方法供外部访问
return name;
}
public void setName(String n) {
name = n;
}
public double getSalary() {
return salary;
}
public void setSalary(double s) {
if(s >= 0) { //检测输入的s
salary = s;
}
}
public void info() {
System.out.println("姓名:" + getName() + ";薪资:" + getSalary());
}
}
public class EncapsulationTest {
public static void main(String[] args) {
Employee emp = new Employee();
//emp.name = "张三"; //name私有,只能通过setName设置
emp.setName("张三");
emp.setSalary(-1000); //加入检测功能,负数不满足条件,salary为默认值
emp.info();
}
}
this关键字
- 非构造方法中,用来表示当前对象,调用成员变量/方法或返回自身
- 构造方法中,用来调用另一个构造方法,必须放在方法首行
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
46class Employee {
private String name;
private double salary;
public Employee(String name) {
this("张三",25); //this调用构造方法,必须放在方法首行!
this.name = name;
}
public Employee(String name,double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
//public void setName(String n) { //n表示参数意义不明确
// name = n;
//}
//public void setName(String name) { //局部变量与成员变量重名,方法内部优先使用局部变量,程序错误
// name = name;
//}
public void setName(String name) { //形参name值传递给当前对象.成员变量
this.name = name; //用this关键字表示当前对象或当前类的一个实例,用this调用对象的所有方法和属性
}
public double getSalary() {
return salary;
}
public void setSalary(double s) {
salary = s;
}
public void info() {
System.out.println("姓名:" + getName() + ";薪资:" + getSalary());
}
public Employee returnthis() { //返回Employee类
return this; //return this返回当前对象
}
}
public class ThisTest {
public static void main(String[] args) {
Employee emp = new Employee("张三"); //构造方法对实例域初始化(张三),后面更改要用set
emp.setName("李四");
//emp.setSalary(20);
emp.info(); //姓名:李四;薪资:25.0
System.out.println(emp.returnthis()); //part023.Employee@70dea4e
}
}
访问修饰符:Java通过访问修饰符来限制类、属性和方法的访问权限,通常放在语句的最前端
- public:共有的,对所有类可见,如果分布在不同包。需要导包
- protected:受保护的,对同一包内的类和所有子类(无论在不在同一包内)可见
- (默认):同一包内可见
- private: 私有的,仅本类可见
继承
- 继承:子类继承父类,继承除构造方法外所有属性和方法,并可以在此基础上拓展,提高代码复用性;”is-a”关系是继承的明显特征。
定义子类:关键字extends表示继承,子类比超类拥有的功能更加丰富
1
2
3
4
5
6
7
8
9
10class Employee { //定义父类Employee
private String name;
private double salary;
getter、setter方法...
}
class Manager extends Employee { //定义子类Manager,继承自Employee
private double bonus; //拓展定义bonus属性
getter、setter方法...
}覆写 override 区别方法重载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Employee { //定义父类Employee
private String name;
private double salary;
getter、setter方法...
}
class Manager extends Employee { //定义子类Manager,继承自Employee
private double bonus; //拓展定义bonus属性
getter、setter方法...
public double getSalary() { //此处覆写getsalary方法
//return salary + bonus; 报错:不能直接访问salary域
//return getSalary() + bonus; 报错:无限调用自身,直至崩溃
return super.getSalary() + bonus; //关键字super表示调用父类的getSalary()方法
}
}子类对象的实例化过程 隐藏super语句 this与super区别
- 子类并没有继承父类的构造方法,只是子类实例化对象时,会默认先调用父类的无参构造器(相当于默认super())
- 如果想调用父类的其他带参构造器,需要在子类构造器首行添加super()语句!
如果父类没有无参构造器,而子类的构造器中又没有显式调用父类的其他构造器,则编译错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Emoloyee {
String name;
double salary;
public Emoloyee() { //父类无参构造方法
System.out.println("父类Employee的无参构造方法");
}
}
class Manager extends Emoloyee {
}
public class InheritanceTest {
public static void main(String[] args) {
//对象实例化中,调用了父类的无参构造方法,是否说明子类继承了父类构造方法?
Manager m = new Manager(); //输出:父类Employee的无参构造方法
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class Emoloyee {
String name;
double salary;
public Emoloyee() { //父类无参构造方法
System.out.println("父类Employee的无参构造方法");
}
public Employee(String name) {
System.out.println("父类Employee的有参构造方法");
}
}
class Manager extends Emoloyee {
public Manager(String name) {
super(name);
System.out.println("子类Manager的有参构造方法");
}
}
public class InheritanceTest {
public static void main(String[] args) {
//对象实例化中,调用了父类的有参构造方法和自身的有参构造方法
Manager m = new Manager("张三"); 输出:父类Employee的有参构造方法 子类Manager的有参构造方法
}
}
super关键字:
- 继承层次:继承可以多层继承,比如C继承自B,B继承自A;但不允许多继承,即C既继承A,也继承B;关于Java多继承的实现方式,参考接口内容。
- final
- 强制类型转换
- 抽象类:
Object:所有类的超类
Object:Object类是Java中所有的基类,如果在类的声明中未使用extends关键字指明其基类,则默认基类为Object类;
1
2
3
4
5
6
7public class Person{
...
}
等价于
public class Person extends Object {
...
}equals方法
- 深入==与equals
- hashCode方法
- toString方法
多态
- 对象转型(具有继承关系)
- 向上转型:子类对象转换为父类对象(Employee->Manager)
- 向下转型:父类对象转换为子类对象(Manager->Employee)
1
2
- 动态绑定与多态