学习Java第四天
单例模式
三元素:
- 构造结构私有化
- 静态属性指向实例
- public static的 getInstance方法,返回第二步的静态属性
饿汉式单例模式
GiantDragon 应该只有一只,通过私有化其构造方法,使得外部无法通过new 得到新的实例。
GiantDragon 提供了一个public static的getInstance方法,外部调用者通过该方法获取12行定义的对象,而且每一次都是获取同一个对象。 从而达到单例的目的。
这种单例模式又叫做饿汉式单例模式,无论如何都会创建一个实例
饿汉式是立即加载的方式,无论是否会用到这个对象,都会加载。
如果在构造方法里写了性能消耗较大,占时较久的代码,比如建立与数据库的连接,那么就会在启动的时候感觉稍微有些卡顿。
package charactor;
public class GiantDragon {
//私有化构造方法使得该类无法在外部通过new 进行实例化
private GiantDragon(){
}
//准备一个类属性,指向一个实例化对象。 因为是类属性,所以只有一个
private static GiantDragon instance = new GiantDragon();
//public static 方法,提供给调用者获取12行定义的对象
public static GiantDragon getInstance(){
return instance;
}
}
懒汉式单例模式
懒汉式单例模式与饿汉式单例模式不同,只有在调用getInstance的时候,才会创建实例
懒汉式,是延迟加载的方式,只有使用的时候才会加载。 并且有线程安全的考量(鉴于同学们学习的进度,暂时不对线程的章节做展开)。
使用懒汉式,在启动的时候,会感觉到比饿汉式略快,因为并没有做对象的实例化。 但是在第一次调用的时候,会进行实例化操作,感觉上就略慢。
package charactor;
public class GiantDragon {
//私有化构造方法使得该类无法在外部通过new 进行实例化
private GiantDragon(){
}
//准备一个类属性,用于指向一个实例化对象,但是暂时指向null
private static GiantDragon instance;
//public static 方法,返回实例对象
public static GiantDragon getInstance(){
//第一次访问的时候,发现instance没有指向任何对象,这时实例化一个对象
if(null==instance){
instance = new GiantDragon();
}
//返回 instance指向的对象
return instance;
}
}
单例模式小结
在应用中,看任务需求选取合适的单例模式:
if(业务上允许有比较充分的启动和初始化时间)
{使用饿汉式;}else
使用懒汉式;
枚举类型
假设在使用switch的时候,不是使用枚举,而是使用int,而int的取值范围就不只是1-4,有可能取一个超出1-4之间的值,这样判断结果就似是而非了。(因为只有4个季节)
但是使用枚举,就能把范围死死的限定在这四个当中。
public enum HeroType{
TANK,WIZARD,ASSASSIN,ASSIST,WARRIOR,RANGED,PUSH,FARMING
}
public static void main(String[] args)
{
/* Hero Ezreal=new Hero();
Ezreal.name="伊泽瑞尔";
Ezreal.hp=520;
Ezreal.armor=13.14f;
Ezreal.moveSpeed=520;
Hero Lux=new Hero();
Lux.name="拉克丝";
Lux.hp=408;
Lux.armor=13.14f;
Lux.moveSpeed=520; */
for(HeroType s:HeroType.values()){
System.out.println(s);
switch (s){
case TANK:
System.out.println("坦克");
break;
case WIZARD:
System.out.println("法师");
break;
case ASSASSIN:
System.out.println("刺客");
break;
case ASSIST:
System.out.println("辅助");
break;
case WARRIOR:
System.out.println("近战");
break;
case RANGED:
System.out.println("远程");
break;
case PUSH:
System.out.println("推进");
break;
case FARMING:
System.out.println("打野");
break;
}
}
枚举类型学习小结
枚举类型使用增强型for循环即可简单遍历。
接口的初步了解
实现某个接口,就相当于承诺了某种约定
所以,实现了AD这个接口,就必须提供AD接口中声明的方法physicAttack()
1.AD接口
package charactor;
public interface AD {
//物理攻击
public void physicAttack();
}
2.AP接口
package charactor;
public interface AP {
public void magicAttack();
}
3.实现了ADAP接口的类
package charactor;
public class ADAPHero extends Hero implements AD,AP{
public void magicAttack(){
System.out.println("进行魔法攻击");
}
public void physicAttack(){
System.out.println("进行物理攻击");
}
}
接口学习小结
在coding过程中,我们会发现如果不在实现接口的类中提供接口声明的方法,IDEA会报错,我们更能理解接口的**“约定”**为何意。
对象转型
子类转父类:向上转型
一定会成功
package charactor;
public class Hero {
public String name;
protected float hp;
public static void main(String[] args) {
Hero h = new Hero();
ADHero ad = new ADHero();
//类型转换指的是把一个引用所指向的对象的类型,转换为另一个引用的类型
//把ad引用所指向的对象的类型是ADHero
//h引用的类型是Hero
//把ADHero当做Hero使用,一定可以
h = ad;
}
}
父类转子类:向下转型
不一定会成功,如下
package charactor;
import charactor1.Support;
public class Hero {
public String name;
protected float hp;
public static void main(String[] args) {
Hero h =new Hero();
ADHero ad = new ADHero();
Support s =new Support();
h = ad;
ad = (ADHero) h;
h = s;
ad = (ADHero)h;
}
}
没有继承关系的两个类互相转换
一定会失败,因为没有关系。在此不赘述。
实现类转换成接口(向上转型)
引用ad指向的对象是ADHero类型,这个类型实现了AD接口
把一个ADHero类型转换为AD接口
从语义上来讲,把一个ADHero当做AD来使用,而AD接口只有一个physicAttack方法,这就意味着转换后就有可能要调用physicAttack方法,而ADHero一定是有physicAttack方法的,所以转换是能成功的。
package charactor;
public class Hero {
public String name;
protected float hp;
public static void main(String[] args) {
ADHero ad = new ADHero();
AD adi = ad;
}
}
接口转换成实现类(向下转型)
不一定能成功
10行: ad引用指向ADHero, 而adi引用是接口类型:AD,实现类转换为接口,是向上转型,所以无需强制转换,并且一定能成功
12行: adi实际上是指向一个ADHero的,所以能够转换成功
14行: adi引用所指向的对象是一个ADHero,要转换为ADAPHero就会失败。
假设能够转换成功,那么就可以使用magicAttack方法,而adi引用所指向的对象ADHero是没有magicAttack方法的。
package charactor;
public class Hero {
public String name;
protected float hp;
public static void main(String[] args) {
ADHero ad = new ADHero();
AD adi = ad;
ADHero adHero = (ADHero) adi;
ADAPHero adapHero = (ADAPHero) adi;
adapHero.magicAttack();
}
}
instanceof应用
instanceof Hero 判断一个引用所指向的对象,是否是Hero类型,或者Hero的子类
package charactor;
public class Hero {
public String name;
protected float hp;
public static void main(String[] args) {
ADHero ad = new ADHero();
APHero ap = new APHero();
Hero h1= ad;
Hero h2= ap;
//判断引用h1指向的对象,是否是ADHero类型
System.out.println(h1 instanceof ADHero);
//判断引用h2指向的对象,是否是APHero类型
System.out.println(h2 instanceof APHero);
//判断引用h1指向的对象,是否是Hero的子类型
System.out.println(h1 instanceof Hero);
}
}
对象转型学习小结
子可以为父;
父难以为子。
方法重写
子类可以继承父类的对象方法
在继承后,重复提供该方法,就叫做方法的重写
又叫覆盖 override
如果没有重写这样的机制,也就是说LifePotion这个类,一旦继承了Item,所有方法都不能修改了。
但是LifePotion又希望提供一点不同的功能,为了达到这个目的,只能放弃继承Item,重新编写所有的属性和方法,然后在编写effect的时候,做一点小改动.
这样就增加了开发时间和维护成本
方法重写学习小结
使用很便利。
多态
1、操作符
同一个操作符在不同情境下,具备不同的作用
如果+号两侧都是整型,那么+代表 数字相加
如果+号两侧,任意一个是字符串,那么+代表字符串连接
2、类
- i1和i2都是Item类型
- 都调用effect方法
- 输出不同的结果
package property;
public class Item {
String name;
int price;
public void buy(){
System.out.println("购买");
}
public void effect() {
System.out.println("物品使用后,可以有效果 ");
}
public static void main(String[] args) {
Item i1= new LifePotion();
Item i2 = new MagicPotion();
System.out.print("i1 是Item类型,执行effect打印:");
i1.effect();
System.out.print("i2也是Item类型,执行effect打印:");
i2.effect();
}
}
类多态的条件
要实现类的多态,需要如下条件
- 父类(接口)引用指向子类对象
- 调用的方法有重写
练习
Hero类
public void kill(Mortal m){
m.die();
}
public static void main(String[] args)
{
Hero garen=new Hero();
ADHero ezreal=new ADHero();
APHero lux=new APHero();
ADAPHero shark=new ADAPHero();
garen.kill(lux);
garen.kill(ezreal);
garen.kill(shark);
}
ADHero类
public void die() {
System.out.println("该名AD英雄已阵亡");
}
以此类推
…
Mortal接口
public interface Mortal {
public void die();
}
学习小结
感觉用的很是舒服哈哈。
今天的学习就到这里,分享一下我的学习资源
https://how2j.cn?p=144753
希望记录我学习进度的同时也能帮助到大家