interface,用来规定类应该有什么什么行为,因此接口中最具体的成员就是抽象方法。另外,jdk8中出现了默认方法和静态方法,jdk9中出现了私有方法。接口可以定义常量。
接口可以被类实现。一个类实现某个接口就会实现接口中的方法,那么该类就具有了接口锁规定的功能,因此,接口是用来规定类应具有什么功能。
二、接口的实现类实现接口使用implements关键字,一个类可以同时实现多个接口。
三、接口的继承接口可以继承其他接口,使用extends关键字,可以同时继承多个接口。
如果类所实现的接口本身继承了其他的接口,这些接口中的方法在类中都要实现
四、抽象类与接口的区别- 抽象类本质上是类,他可以具有类可拥有的成员。接口不是类,只能拥有接口所规定的成员,其中最主要的成员是抽象方法。
- 抽象类的使用场合在于需要构建具有继承关系的父类及子类,设计的初衷在于类中的某些行为无法进行具体化。因此抽象类与子类是同一种类型,此时,子类的任务就是把抽象类中的抽象方法进行具体实现。接口的使用场合在于当前类的功能必须满足接口的规定。接口是用来规定功能的的。
- 子类只能继承一个抽象类,但可以实现多个接口(继承只能1v1,)
同一种行为表现为多种形态。
-
传统的教科书认为多态有两种
(1)方法的重写。(同名同参,返回实现不同)(在子类)
(2)方法的重载。(同名不同参数,返回实现不同)(在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。)
所谓重载,是在同一个类中,方法的名称相同,但是参数不同(类型不同,个数不同,及有参与无参)。无论返回值是什么,无论修饰符是什么。因此,重载就是一个类中的同一种行为有不同的实现细节。
-
现实的多态解释
声明一个对象时,可以用对象所属类型的超类(super/父类)或对象所实现的接口类型来声明。
(1)向上转型:基于引用类型的对象,可以用超类型或接口来声明对象的类型,或者把子类型的对象转换为超类型的对象。
39行:(动)SmallDag sd = new SmallDag(“小白”) //这里的sd是SmallDog类型,在运行期jvm也可以识别出它是SmallDog类型
40行:(静)BigDog bd=sd; //bd是BigDog类型,在编译期 、编译期人为bd是BigDog类型,赋值的动作在运行期发生,jvm在运行期会识别出bd是SmallDog类型41行:结果为true,说明两者 bd与sd是同一个对象
结论:同一个对象可以具有不同的类型,主要体现在编译期和运行时原因:这两个阶段对类型的识别方式不一样。编译期看的是类型的声明,运行期看对象属于哪个字节码,而bd就是对sd的引用对象的重新引用
所以:bd和sd引用的同一个对象,返回结果
判断一个变量所引用对象的真是类型的依据在于创建对象时使用的哪个对象,也就是看的 new SmallDag(“小白”)
返回结果为true:说明是同一个对象
子类可看做是特殊的父类, 所以父类类型的引用可以指向子类的对象:向上转型(upcasting)。
父类对象bd(大白)调用吃,是子类的方法
结论一:向上转型的对象,使用的属性如果父类和子类都有(同名),使用父类的属性。调用的方法如果子类重写了父类的方法则重写子类的方法
(2)向下转型
运行期看new后面的,编译期看前面的
sd强制类型转换为小狗类型调用小狗的run()方法。
**注意:**向下转型如果转换的结果类型与源类型不具有继承关系,运行时会抛出异常(编译器提示:转换异常、运行结果:运行时异常)
(3)向上或向下转型是多态的表现,具体理解就是同一对象在编译期和运行期可以具有不同的类型,这就造成了通过对象在调用方法和引用属性时会产生容易混淆的问题,另一个就是容易发生运行时类型转换的异常
(4)如果一个类实现了某个接口,也可以用该接口声明该类的对象,这也属于向上转型的一种用法
接口属于引用类型的原因找到了,这里接口可以用作调用方法。
六、权限修饰符| public | protected | default (空的) | private | |
|---|---|---|---|---|
| 同一类中 | √ | √ | √ | √ |
| 同一包中(子类与无关类) | √ | √ | √ | |
| 不同包的子类 | √ | √ | ||
| 不同包中的无关类 | √ |
-
如果一个类定义在另一个类中,此类就是内部类,
创建内部类对象格式:
外部类名.内部类名 对象名 = new 外部类型().new 内部类型()
- 内部类的权限修饰符可以使private,外部类不行。
- 内部类中可以使用外部类的成员变量也可以调用外部类对象的成员方法。
- 非私有的外部类可以被外部访问。
-
一个模仿咖啡店售卖咖啡的例子
package lession.coffer; public class CafeShop { public static final String Coco = "coco咖啡"; public static final String Tanshao = "炭烧咖啡"; public static final String Lanshan = "蓝山咖啡"; public Cafe shop(String type){ //这里的类型是Cafe方法,返回的是咖啡 Cafe cafe = new Cafe(type);//返回的是Cafe中的cafe类型 return cafe; } //定义内部类 private class Cafe implements inf{ private String type; //"咖啡的种类" public Cafe(String type){ //当全局变量跟局部变量重名时,表示使用全局变量(此时this指代本类对象) this.type=type; //获得咖啡种类 } //体现店面 @Override public String toString() { return "一杯"+type+"的kafei"; } } //定义一个公共的接口 (这里用的大括号) public interface inf{} }public class demo { public static void main(String[] args) { CafeShop cafeShop = new CafeShop(); CafeShop.inf cafe=cafeShop.shop(CafeShop.Coco); System.out.println(cafe); } }输出结果:一杯coco咖啡的kafei
-
匿名内部类
//直接创建接口的对象 sport sp=new sport() { @Override public void jump() { //动态创建,没有基于一个类,而是jvm组装起来的,运行完了就结束了 System.out.println("我们欢快的跳了起来"); } @Override public void run() { } }; sp.jump();(1).匿名内部类一般在方法内使用,也就是接口、抽象类或其他类结合new关键字创建对象的特殊方法
(2).创建匿名内部类是使用子类或者接口实现类的简单方法(偷懒)
子类重写父类的方法,子类方法的修饰符的权限方位必须大于等于父类方法的修饰符号(父类:default---->子类修饰符:protectedpublic)
其他:
//This object (which is already a string!) is itself returned.
Returns:
the string itself.
//这个对象(已经是一个字符串了!)本身会被返回字符串本身。
public String toString() {
return this;
}
重写toString() 只会对类生效,并不能对字符串生效
为什么要重写toString()方法
当需要将一个对象输出到显示器时,通常要调用他的toString()方法,将对象的内容转换为字符串.java中的所有类默认都有一个toString()方法。
碰到的问题:使用toString和没调用是一样的(返回值是对象地址,这里用了内部类,自定义方法): 父类中没重写
需求实现""
-
模拟玩家选择角色。
-
定义接口FightAble:
- 抽象方法:specialFight。
- 默认方法:commonFight,方法中打印"普通打击"。
-
定义战士类:
- 实现FightAble接口,重写方法中打印"武器攻击"。
-
定义法师类:
- 实现FightAble接口,重写方法中打印"法术攻击"。
-
定义玩家类Player:
- 成员方法:FightAble select(String str),根据指令选择角色。
- 法力角色,选择法师。
- 武力角色,选择战士。
- 成员方法:FightAble select(String str),根据指令选择角色。
代码:
public interface FightAble {
//默认方法,普通打击
default void commonFight(){
System.out.println("普通打击");;
}
//抽象方法 特殊
void specialFight();
}
public class Master implements FightAble{
final String M="法力角色";
@Override
public void specialFight() {
System.out.println("武器打击");
}
@Override
public String toString() {
return M;
}
}
public class Warrior implements FightAble{
final String W="武力角色";
//我叫武器大师,这里是我家
@Override
public String toString() {
return W;
}
@Override
public void specialFight() {
System.out.println("法术攻击");
}
}
public class player {
Master m1=new Master();//法师
Warrior w1=new Warrior();//战士
String str1 =new String("法力角色");
String str2 =new String("武力角色");
public FightAble select(String str){
if (str.equals(str1)){
return m1;
}
if (str.equals(str2)){
return w1;
}
return null;
}
@Override
public String toString() {
return " 玩家牛马大师选的"+m1+player.class;
}
}
public class demo {
public static void main(String[] args) {
//新建玩家
player p=new player();
//选择建立法师角色(也可以改进为输入角色)
FightAble f=p.select("法力角色");
System.out.println("选择角色:"+f);
//攻击:普通/法术
f.commonFight();
f.specialFight();
System.out.println("=================");
FightAble w=p.select("武力角色");
System.out.println("选择角色:"+w+"玩家的地址"+p);
w.specialFight();
w.commonFight();
}
小结:
改成输出属性值
在父类中重写toString();方法
快捷键:Alt+Insert
数值打印地址值是因为没重写toString();方法
在父类中重写toString();方法
这样会直接掉用object中的toString();方法
组合、继承、接口的使用场景
| 名称 | 使用方法 | 使用场景 |
|---|---|---|
| 组合has-a | 将这些公共方法写到一个类中,然后将该类作为一个成员变量来使用。这样就达到了复用的目的,可读性和可扩展性也得到了提升。 | |
| 继承is-a | 父类的所有属性和方法都可以被子类访问和调用,关键字extend | 代码复用 |
| 接口 | 接口的修饰符是interface。作用是定义方法,方法的具体实现由子类实现,关键字implements,一个类可以实现多个接口 | 需要构建具有继承关系的父类及子类 |
- 接口中的方法一定是抽象方法,抽象类的方法可以抽象方法,并且抽象方法一定是没有方法体的
- 抽象类和接口都不能被定义为私有的或final的,否则不能被继承或实现。
Java理解误区——方法的重载是多态性的一种体现?
https://blog.csdn.net/qq_42937522/article/details/106563188
数据转换:
Random random= new Random();
double num=random.nextDouble()*100;
System.out.println("随机数为"+"n"+num);
//方法1
System.out.println("转换后为:"+"n"+String.format("%.2f", num)); //String.format("%.2f", num)保留两个小数
//方法2 #.00 表示两位小数
DecimalFormat df = new DecimalFormat("#0.00");
System.out.println("转换后(2):"+df.format(num));
// 方法3 BigDecimal银行业务用的函数类
BigDecimal bg = new BigDecimal(num);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doublevalue();
System.out.println("转换后(3):"+f1);
//方法4
NumberFormat nf = NumberFormat.getNumberInstance();
//digits 显示的数字位数 为格式化对象设定小数点后的显示的最多位,显示的最后位是舍入的
nf.setMaximumFractionDigits(2);
System.out.println("转换后(4):"+nf.format(num));



