文章目录
第3天
1.多态
目标:多态的入门概述。
面向对象的三大特征:封装,继承,多态。
多态的形式:
父类类型 对象名称 = new 子类构造器;
接口 对象名称 = new 实现类构造器;
父类类型的范围 > 子类类型范围的。
多态的概念:
同一个类型的对象,执行同一个行为,在不同的状态下会表现出不同的行为特征。
多态的识别技巧:
对于方法的调用:编译看左边,运行看右边。
对于变量的调用:编译看左边,运行看左边。
多态的使用前提:
(1) 必须存在继承或者实现关系。
(2) 必须存在父类类型的变量引用子类类型的对象。
(3) 需要存在方法重写。
小结:
记住多态的形式,识别,概念等语法即可!
public class PolymorphicDemo {
public static void main(String[] args) {
// 父类类型 对象名称 = new 子类构造器;
Animal dlam = new Cat();
dlam.run(); // 对于方法的调用:编译看左边,运行看右边。
System.out.println(dlam.name); // 对于变量的调用:编译看左边,运行看左边。
Animal taiDi = new Dog();
taiDi.run(); // 对于方法的调用:编译看左边,运行看右边。
System.out.println(taiDi.name); // 对于变量的调用:编译看左边,运行看左边。
}
}
class Dog extends Animal{
public String name = "🐶名称Dog";
@Override
public void run(){
System.out.println("🐕跑的贼快~~~~!");
}
}
class Cat extends Animal{
public String name = "🐱名称Cat";
@Override
public void run(){
System.out.println("🐱跑的飞快~~~~!");
}
}
class Animal{
public String name = "动物名称Animal";
public void run(){
System.out.println("动物跑!");
}
}
目标:多态的优劣势。
优势:
1.在多态形式下,右边对象可以实现组件化切换,业务功能也随之改变,
便于扩展和维护。可以实现类与类之间的解耦。
2.实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,
可以传入一切子类对象进行方法的调用,更能体现出多态的扩展性与便利。
劣势:
1.多态形式下,不能直接调用子类特有的功能。编译看左边!! 左边
父类中没有子类独有的功能,所以代码在编译阶段就直接报错了!
小结:
记住以上语法!
目标:引用数据类型的自动类型转换。
在基础班学过了基本数据类型的转换。
1.小范围类型的变量或者值可以直接赋值
给大范围类型的变量。
2.大范围类型的变量或者值必须强制类型转换
给小范围类型的变量。
引用数据类型转换的思想是一样的:
父类类型的范围 > 子类类型的范围。
Animal Cat
引用数据类型的自动类型转换语法:
1.子类类型的对象或者变量可以自动类型转换
赋值给父类类型的变量。
小结:
记住语法!
引用类型的自动类型转换并不能解决多态的劣势。
// 1.引用类型的自动类型转换:小范围的对象赋值给大范围的变量
Animal a = new Cat();
class Animal{}
class Cat extends Animal{}
目标:引用类型强制类型转换
引用类型强制类型转换的语法:
1.父类类型的变量或者对象必须强制类型转换成子类类型的变量,否则报错!
强制类型转换的格式:
类型 变量名称 = (类型)(对象或者变量)
注意:有继承/实现关系的两个类型就可以进行强制类型转换,编译阶段一定不报错!
但是运行阶段可能出现:类型转换异常 ClassCastException
Java建议在进行强制类型转换之前先判断变量的真实类型,再强制类型转换!
变量 instanceof 类型
: 判断前面的变量是否是后面的类型或者其子类类型才会返回true,
小结:
有继承/实现关系的两个类型就可以进行强制类型转换,编译阶段一定不报错!
但是运行阶段可能出现:类型转换异常 ClassCastException
Java建议在进行强制类型转换之前先判断变量的真实类型,再强制类型转换!
变量 instanceof 类型: 判断前面的变量是否是后面的类型或者其子类类型才会返回true,
// 2.多态下类型转换异常问题研究(重点)
Animal a1 = new Cat();
Wolf w1 = (Wolf) a1; // 编译阶段没有报错!在运行阶段出现ClassCastException类型转换成!
if(a1 instanceof Cat){
Cat c1 = (Cat) a1;
c1.catchMouse();
}else if(a1 instanceof Wolf){
Wolf w1 = (Wolf) a1;
w1.catchSheep();
}
2.内部类
目标:内部类的概述和分类。
内部类是类的五大成分之一:成员变量,方法,构造器,代码块,内部类。
什么是内部类?
定义在一个类里面的类就是内部类。
内部类有什么用?
可以提供更好的封装性, 内部类有更多权限修饰符 , 封装性有更多的控制。
可以体现出组件的思想。
内部类的分类:
(1)静态内部类。
(2)实例内部类。(成员内部类)
(3)局部内部类。
(4)匿名内部类。(重点)
小结:
匿名内部类是我们的重点。
目标:静态内部类的研究(了解语法即可)
什么是静态内部类?
有static修饰,属于外部类本身,会加载一次。
静态内部类中的成分研究:
类有的成分它都有,静态内部类属于外部类本身,只会加载一次
所以它的特点与外部类是完全一样的,只是位置在别人里面而已。
外部类=宿主
内部类=寄生
静态内部类的访问格式:
外部类名称.内部类名称
静态内部类创建对象的格式:
外部类名称.内部类名称 对象名称 = new 外部类名称.内部类构造器;
静态内部类的访问拓展:
静态内部类中是否可以直接访问外部类的静态成员?可以的,外部类的静态成员只有一份,可以被共享!
静态内部类中是否可以直接访问外部类的实例成员?不可以的,外部类的是成员必须用外部类对象访问!!
小结:
静态内部类属于外部类本身,只会加载一次
所以它的特点与外部类是完全一样的,只是位置在别人里面而已。
class Outter{
public static int age1 = 12;
private double salary;
// 静态内部类:有static修饰,属于外部类本身,只会加载一次
public static class Inner{
public void show() {
System.out.println(age1);//12
System.out.println(salary);//访问不到
}
}
}
public class InnerClass {
public static void main(String[] args) {
// 外部类名称.内部类名称 对象名称 = new 外部类名称.内部类构造器
Outter.Inner in = new Outter.Inner();
in.show();
}
}
目标:内部类_实例内部类(成员内部类)(了解语法为主)
什么是实例内部类:
无static修饰的内部类,属于外部类的每个对象的,跟着对象一起加载的。
实例内部类的成分特点:
实例内部类中不能定义静态成员,其他都可以定义。
可以定义常量。
实例内部类的访问格式:
外部类名称.内部类名称。
创建对象的格式:
外部类名称.内部类名称 对象名称 = new 外部类构造器.new 内部构造器;
拓展:
实例内部类中是否可以直接访问外部类的静态成员?可以的,外部类的静态成员可以被共享访问!
实例内部类中是否可以访问外部类的实例成员?可以的,实例内部类属于外部类对象,可以直接访问当前外部类对象
的实例成员!
小结:
实例内部类属于外部类对象,需要用外部类对象一起加载,
实例内部类可以访问外部类的全部成员!
目标:局部内部类。(几乎不用)
定义在方法中,在构造器中,代码块中,for循环中定义的内部类,就是局部内部类。
局部内部类中的成分特点:
只能定义实例成员,不能定义静态成员
可以定义常量的。
小结:
局部内部类没啥用。
public static void test(){
class Animal{
}
class Cat extends Animal{
}
}
目标:匿名内部类的概述
什么是匿名内部类?
就是一个没有名字的局部内部类。
匿名内部类目的是为了:简化代码,也是开发中常用的形式。
匿名内部类的格式:
new 类名|抽象类|接口(形参){
方法重写。
}
匿名内部类的特点:
1.匿名内部类是一个没有名字的内部类。
2.匿名内部类一旦写出来,就会立即创建一个匿名内部类的对象返回。
3.匿名内部类的对象的类型相当于是当前new的那个的类型的子类类型
。
小结:
1.匿名内部类是一个没有名字的内部类。
2.匿名内部类一旦写出来,就会立即创建一个匿名内部类的对象返回。
3.匿名内部类的对象的类型相当于是当前new的那个的类型的子类类型。
public class Anonymity {
public static void main(String[] args) {
Animal a2 = new Animal() {
@Override
public void run() {
System.out.println("人跑的快");
}
};
a2.go();
}
}
abstract class Animal{
public abstract void run();
public void go(){
System.out.println("开始go~~~");
}
}
3.包和权限修饰符
目标:包和权限修饰符。
包:
分门别类的管理各种不同的技术。
企业的代码必须用包区分。便于管理技术,扩展技术,阅读技术。
定义包的格式:package 包名; 必须放在类名的最上面。一般工具已经帮我们做好了。
包名的命名规范:
一般是公司域名的倒写+技术名称:
http://www.itheima.com => com.itheima.技术名称
包名建议全部用英文,多个单词用”.“连接,必须是合法标识符,不能用关键字
注意:
相同包下的类可以直接访问。
不同包下的类必须导包,才可以使用!
导包格式:import 包名.类名;
目标:权限修饰符。
权限修饰符:有四种(private -> 缺省 -> protected - > public )
可以修饰成员变量,修饰方法,修饰构造器,内部类,不同修饰符修饰的成员能够被访问的权限将受到限制!
四种修饰符的访问权限范围:
private 缺省 protected public
本类中 √ √ √ √
本包下其他类中 X √ √ √
其他包下的子类中 X X √ √
其他包下的类中 X X X √
4.Object类
目标:常用API的学习-Object类的toString方法使用详解。
引入
包:java.lang.Object
Object类是Java中的祖宗类。
一个类要么默认继承了Object类,要么间接继承了Object类。
Object类的方法是一切子类都可以直接使用的,所以我们要学习Object类的方法。
Object类的常用方法:
(1)public String toString():
– 默认是返回当前对象在堆内存中的地址信息:com.itheima._12Object类的详细使用.Student@735b478
– 默认的地址信息格式:类的全限名@内存地址
– 直接输出对象名称,默认会自动调用toString()方法,所以输出对象toString()调用可以省略不写
– 开发中直接输出对象,默认输出对象的地址其实是毫无意义的。开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息!所以父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息输出!!
小结:
toString()默认是返回当前对象在堆内存中的地址信息:
开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息!
所以父类toString()方法存在的意义就是为了被子类重写,重写toString可以看到对象的内容信息。
(2)public boolean equals(Object o):
– 默认是比较两个对象的地址是否相同。相同返回true,反之。
– 直接比较两个对象的地址是否相同完全可以用“==”替代equals。所以equals存在的意义是为了被子类重写,以便程序员可以自己来定制比较规则。
– 需求:只要两个对象的内容一样,我们就认为他们是相等的。
小结:
equals存在的意义是为了被子类重写,以便程序员可以自己来定制比较规则。
目标:Objects类的使用。
Objects类与Object还是继承关系。
Objects类是从JDK 1.7开始之后才有的。
Objects的方法:
1.public static boolean equals(Object a, Object b)
– 比较两个对象的。
– 底层进行非空判断,从而可以避免空指针异常。更安全!!推荐使用!!
public static boolean equals(Object a, Object b) {
return a == b || a != null && a.equals(b);
}
2.public static boolean isNull(Object obj)
– 判断变量是否为null ,为null返回true ,反之!
Student s1 = null;
Student s2 = new Student();
System.out.println(Objects.equals(s1 , s2)); // 可以避免空指针异常。更安全!! false
// System.out.println(s1.equals(s2)); // 空指针异常
// 询问s1是否为null 为null返回true ,反之!
System.out.println(Objects.isNull(s1));
System.out.println(s1 == null); // 可以直接用==判断也可以!
5.Date日期类
目标:Date日期类的使用。
Java是面向对象的,会用一个类代表一个事物。
Date类在Java中代表的是系统当前此刻日期时间对象。
Date类:
包:java.util.Date。
构造器:
– public Date():创建当前系统的此刻日期时间对象。
– public Date(long time):
方法:
– public long getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来走过的总的毫秒数。
时间记录的两种方式:
a.Date日期对象。
b.时间毫秒值:从1970-01-01 00:00:00开始走到此刻的总的毫秒值。 1s = 1000ms
小结:
Date可以代表系统当前此刻日期时间对象。
时间记录的两种方式:
Date日期对象。
时间毫秒值:从1970-01-01 00:00:00开始走到此刻的总的毫秒值。 1s = 1000ms
// a.创建一个日期对象代表了系统此刻日期时间对象
Date d = new Date();
System.out.println(d); //Sun Aug 07 10:36:56 CST 2022
// b.拿当前日期对象的时间毫秒值
long time = d.getTime();
System.out.println(time);
目标:Date类的有参数构造器的使用。
构造器:
– public Date():创建当前系统的此刻日期时间对象。
– public Date(long time):把时间毫秒值转换成日期对象。
流程:
Date日期对象 -> getTime() -> 时间毫秒值
时间毫秒值 -> new Date(时间毫秒值) -> Date日期对象
小结:
public Date(long time):把时间毫秒值转换成日期对象。
// 需求:问121s以后的时间是多少。
// 1.拿到此刻日期对象
Date d = new Date();
System.out.println(d);
// 2.拿到此刻日期对象的时间毫秒值 往后走 121 s
long time = d.getTime() + 121*1000;
// 3.把时间毫秒值转换成日期对象。
Date d1 = new Date(time);
System.out.println(d1);
6.DateFormat日期格式化类
目标:DateFormat简单日期格式化类的使用。
引入:
我们之前得到的Date日期对象或者时间毫秒值的时间形式
开发中并不喜欢,不符合有些时间格式的需求。
DateFormat作用:
1.可以把“日期对象”或者“时间毫秒值”格式化成我们喜欢的时间形式。(格式化时间)
2.可以把字符串的时间形式解析成日期对象。(解析字符串时间)
DateFormat是一个抽象类,不能直接使用,要找它的子类:SimpleDateFormat
我们需要用的是简单日期格式化类:SimpleDateFormat
SimpleDateFormat简单日期格式化类:
包:java.text.SimpleDateFormat
构造器:public SimpleDateFormat(String pattern):
指定时间的格式创建简单日期格式化对象。
方法:
– public String format(Date date):可以把日期对象格式化成我们喜欢的时间形式,返回的是字符串!
– public String format(Object time):可以把时间毫秒值格式化成我们喜欢的时间形式,返回的是字符串!
– public Date parse(String date) throws ParseException:把字符串的时间解析成日期对象
小结:
简单日期格式化类SimpleDateFormat可以把日期对象格式化成我们喜欢的时间形式
– public String format(Date date):可以把日期对象格式化成我们喜欢的时间形式,返回的是字符串!
// 需求:把此刻日期对象格式化成我们喜欢的形式。
// 1.得到此刻日期对象
Date d = new Date();
// 2.创建一个简单日期格式化对象负责格式化日期对象
// 注意:参数是之间的格式。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
// 3.开始调用方法格式化时间得到格式化的字符串时间形式
String rs = sdf.format(d);
System.out.println(rs); //2022年08月07日 15:24:54 周日 下午
拓展:简单日期格式化类SimpleDateFormat格式化时间毫秒值。
// 1.问121s后的时间是多少。格式化输出。
// a.得到此刻日期对象
Date date = new Date();
// b.得到当前时间的时间毫秒值
long time = date.getTime();
time += 121 * 1000;
// c.格式化时间毫秒值
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
System.out.println(sdf.format(time));
目标:简单日期格式化类SimpleDateFormat解析字符串时间成为日期对象。
引入:
Date日期对象 -> 格式化成 -> 喜欢的字符串时间形式。
时间毫秒值 -> 格式化成 -> 喜欢的字符串时间形式。
字符串的时间形式 -> 解析成 -> Date日期对象。
开发中经常会收到字符串的时间,需要转成Date日期对象。"2018-10-11 10:10:22"字符串转换成Date日期对象
// 面试题:请问 “2019-11-04 09:30:30” 往后 1天15小时,30分29s后的时间是多少
// a.定义一个字符串时间
String date = "2019-11-04 09:30:30";
// b.把字符串的时间解析成Date日期对象 。(重点)
// 1.创建一个简单日期格式化对象负责解析字符串的时间成为日期对象
// 注意:参数必须与被解析的时间的格式完全一致,否则执行报错!!
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 2.开始解析成日期对象
Date newDate = sdf.parse(date);
// c.得到日期对象的时间毫秒值 + 往后走 1天15小时,30分29s
long time = newDate.getTime() + (24L *60*60 + 15*60*60 + 30*60 + 29) * 1000;
// d.把时间毫秒值格式化成喜欢的字符串的时间形式!
System.out.println(sdf.format(time));
7.Calendar日历类
目标:日历类Calendar的使用。
Calendar代表了系统此刻日期对应的日历对象。
Calendar是一个抽象类,不能直接创建对象。
Calendar日历类创建日历对象的语法:
Calendar rightNow = Calendar.getInstance();
Calendar的方法:
1.public static Calendar getInstance(): 返回一个日历类的对象。
2.public int get(int field):取日期中的某个字段信息。
3.public void set(int field,int value):修改日历的某个字段信息。
4.public void add(int field,int amount):为某个字段增加/减少指定的值
5.public final Date getTime(): 拿到此刻日期对象。
6.public long getTimeInMillis(): 拿到此刻时间毫秒值
小结:
记住。
// 1.通过调用日历类的静态方法getInstance得到一个当前此刻日期对象对应的日历对象。
Calendar rightNow = Calendar.getInstance();
System.out.println(rightNow);
// 2.获取年:
int year = rightNow.get(Calendar.YEAR);
System.out.println(year);
int mm = rightNow.get(Calendar.MONTH) + 1;
System.out.println(mm);
// 3.一年中的第几天: 308
int days = rightNow.get(Calendar.DAY_OF_YEAR);
System.out.println(days);
// 4.修改日历的信息
//rightNow.set(Calendar.YEAR , 2099);
//System.out.println(rightNow.get(Calendar.YEAR));
// 5.日历可以得到此刻日期对象。
Date d = rightNow.getTime();
System.out.println(d);
// 6.此刻时间毫秒值
long time = rightNow.getTimeInMillis();
System.out.println(time);
// 7.请问701天 15小时后是哪个日期
// 让日历的一年中的第几天往后走 701天!
rightNow.add(Calendar.DAY_OF_YEAR , 701);
rightNow.add(Calendar.HOUR , 15);
long time1 = rightNow.getTimeInMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");
System.out.println(sdf.format(time1));
8.Math类
目标:Math类的使用。
Math用于做数学运算。
Math类中的方法全部是静态方法,直接用类名调用即可。
方法:
方法名 说明
public static int abs(int a) 获取参数a的绝对值
public static double ceil(double a) 向上取整
public static double floor(double a) 向下取整
public static double pow(double a, double b) 获取a的b次幂
public static long round(double a) 四舍五入取整
public static int max(int a, int b) 返回两个int的较大值
public static int min(int a, int b) 返回两个int的较小值
小结:
记住。
// 1.取绝对值:返回正数。
System.out.println(Math.abs(10));
System.out.println(Math.abs(-10.3));
// 2.向上取整: 5
System.out.println(Math.ceil(4.00000001)); // 5.0
// 3.向下取整:4
System.out.println(Math.floor(4.99999999)); // 4.0
// 4.求指数次方
System.out.println(Math.pow(2 , 3)); // 2^3 = 8.0
// 5.四舍五入 10
System.out.println(Math.round(4.49999)); // 4
System.out.println(Math.round(4.500001)); // 5
9.System类
目标:System系统类的使用。
System代表当前系统。
静态方法:
1.public static void exit(int status):终止JVM虚拟机,非0是异常终止。
2.public static long currentTimeMillis():获取当前系统此刻时间毫秒值。
3.可以做数组的拷贝。
arraycopy(Object var0, int var1, Object var2, int var3, int var4);
- 参数一:原数组
- 参数二:从原数组的哪个位置开始赋值。
- 参数三:目标数组
- 参数四:赋值到目标数组的哪个位置
- 参数五:赋值几个。
10.BigDecimal计算浮点型
目标:BigDecimal大数据类。
引入:
浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。
BigDecimal可以解决浮点型运算数据失真的问题。
BigDicimal类:
包:java.math.
创建对象的方式(最好的方式:)
public static BigDecimal valueOf(double val) :包装浮点数成为大数据对象。
方法声明
public BigDecimal add(BigDecimal value) 加法运算
public BigDecimal subtract(BigDecimal value) 减法运算
public BigDecimal multiply(BigDecimal value) 乘法运算
public BigDecimal divide(BigDecimal value) 除法运算
public double doubleValue():把BigDecimal转换成double类型。
double a = 0.1 ;
double b = 0.2 ;
// 1.把浮点数转换成大数据对象运算
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b1 = BigDecimal.valueOf(b);
BigDecimal c1 = a1.add(b1); // 加法
BigDecimal c1 = a1.divide(b1); // 除法
// 结果可能需要继续使用!!!
// BigDecimal只是解决精度问题的手段,double数据才是我们的目的!!
double rs = c1.doubleValue();
11.包装类
目标:包装类。
引入:
Java认为一切皆对象。引用数据类型就是对象了。
但是在Java中8基本数据类型不是对象,只是表示一种数据的类型形式,这8种数据类型显得很突兀。
Java为了一切皆对象的思想统一,把8种基本数据类型转换成对应的类,这个类称为基本数据类型的包装类。
基本数据类型 包装类(引用数据类型)
byte Byte
short Short
int Integer(特殊)
long Long
float Float
double Double
char Character(特殊)
boolean Boolean
自动装箱:可以直接把基本数据类型的值或者变量赋值给包装类。
自动拆箱:可以把包装类的变量直接赋值给基本数据类型。
小结:
自动装箱:可以直接把基本数据类型的值或者变量赋值给包装类。
int a = 12 ;
Integer a1 = 12 ; // 自动装箱
Integer a2 = a ; // 自动装箱
Integer c = 100 ;
int c1 = c ; // 自动拆箱
int d = 12;
Integer d1 = null; // 引用数据类型默认值为null
Integer d2 = 0;
Integer it = Integer.valueOf(12); // 手工装箱!
Integer it3 = 111 ;
int it33 = it3.intValue(); // 手工拆箱