1、多态
1概念:
同一个事物,行为,具有多个不同的表现形式
2多态的格式
1.父类 变量名 = new 子类();
2.接口 变量名 = new 实现类();
3多态的前提
有继承关系 或者 要有方法重写
4多态的“调用方法原理”
【编译看左边,运行看右边】
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。如果子类没有重写该方法,就会调用父类的该方法。
5多态的好处
【提高代码的扩展性】
左边写父类,右边写子类,
方法的参数写父类,调用方法时可以传入各种子类对象,可以避免写很多重载的方法,提高代码的扩展性
6多态的弊端
只能调用父类有的方法,而不能调用子类特有的方法(功能)。
解决办法:引用类型转换之向下转型
7引用类型转换: 子类和父类之间的转换
1.【向上转型】:将子类转成父类,就是多态
父类 变量名 = new 子类();
2.向下转型:将父类转成子类
子类 变量名 = (子类)父类变量;
8用于解决类型转换的异常情况:ClassCastException
为了避免该异常,提供instancof关键字
1、使用格式:变量 instanceof 类名;
//返回值是一个布尔类型
2、作用:判断变量是否是执行的类型,如果返回ture,表示变量是指定的类型
3、使用场景:向下转型前做类型判断
2、内部类
概念:一个写到了另一个类的里面的类称为内部类。(类中类)
应用场景:一个事物内部还有一个事物,内部的事物脱离外部的事物无法独立运行
内部类的分类:
按照内部类在外部类的定义位置划分:
1、成员内部类:在类中方法外定义的类。
(1)定义及使用步骤:1.创建外部类对象;2.根据外部类对象创建内部类对象
(2)优势:内部类可以直接使用外部类的成员
(3)内部类编译后的结果:编译成的class文件样式:外部类名$内部类名.class
(4)可再次划分:
a.【静态内部类】由static修饰的成员内部类
创建静态内部类对象格式:外部类名.内部类名 变量名 = new 外部类名.内部类名();
b.【实例内部类】无static修饰的成员内部类
创建实例内部类对象格式:1、先创建外部类对象hh
2、根据外部类对象创建内部类对象,
【格式】:外部类名.内部类名 对象名 = hh.new 内部类名();
2、局部内部类:在类中方法内定义的类
(1)定义及使用步骤:1.创建外部类对象;2.在定义局部内部类之后,立马使用
(2)优势:内部类可以直接使用外部类的成员
(3)内部类编译后的结果:编译成的class文件样式:外部类名$数字内部类名.class
//此处的数字表示该类中的第几个内部类
(4)可再次划分:
a.【局部内部类】`
b.==【匿名内部类】==没有名字的内部类
<1>创建格式:
new 接口或者类() {
重写方法;
}.方法名();
<2>本质:
四合一
1.定义一个没有名字的类
2.这个没有名字的类实现了前面的接口(接口方法由抽象变具体)
3.创建了这个没有名字的类的对象
4.对象调用了方法
<3>如果需要多次调用方法,需要保存这个匿名内部类创建的对象(实际上是运用了多态)
格式:接口名 变量名 = new 实现类();
Smokeable sm = new Smokeable() {
@Override
public void smoking() {
System.out.println("站着抽烟");
}
};
sm.smoking();
sm.smoking();
sm.smoking();
<4>匿名对象的使用场景
匿名内部类一般是作为参数传入。
(当方法参数是接口的时候,可以传入倪敏内部类对象,代码简单)
public class Demo10 {
public static void main(String[] args) {
Teacher t = new Teacher();
Student s = new Student();
goSwimming(t);
goSwimming(s);
// 方法的参数是接口,我们可以传入匿名内部类对象 =======================》重点!!!!!
goSwimming(new Swimmable() {
@Override
public void swimming() {
System.out.println("随便游");
}
});
}
// 接口名 变量名 = new 实现类(); 多态
// goSwimming(t); Swimmable s = t; Swimmable s = new Teacher();
// goSwimming(s); Swimmable s = s; Swimmable s = new Student();
// 我请一帮会游泳的人去游泳(很多人(对象)都可以去游泳,老师,学生等等,如果不使用接口作为方法参数,会让我们白白写很多重载方法。
public static void goSwimming(Swimmable s) {
s.swimming();
}
// public static void goSwimming(Teacher s) {
// }
}
3、代码块
1静态代码块
定义位置:类中方法外
特点:静态代码块一个类只会自动执行一次
2实例(构造)代码块
定义位置:类中方法外
特点:构造代码块是在每次执行构造方法前自动执行
本质:经过反编译工具可知,实际上构造代码块里面的代码会放到构造方法的最前面
Person类:
public class Person {
public static final int abc;
// 静态代码块
static {
abc = 10;
System.out.println("我是静态代码块");
}
// 构造代码块
{
System.out.println("我是构造代码块");
}
public Person() {
System.out.println("我是Person的无参构造方法");
}
}
测试类:
public class Demo11 {
public static void main(String[] args) {
// 创建两个对象
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
}
}
/*
执行效果:
我是静态代码块
我是构造代码块
我是Person的无参构造方法
我是构造代码块
我是Person的无参构造方法
我是构造代码块
我是Person的无参构造方法
*/
4、访问修饰符
public: 公开的,公共的
protected: 受保护的
(default)(什么都不写): 缺省|默认的
private: 私有的
修饰范围:public > protected > (default) > private
常用:
public: 所有地方都能使用
private: 只有本类能够使用
不常用的:
缺省的/默认的: 给同一包中的类使用
protected: 给子类使用的(无论本包还是其他包路径下的类)
5、Object类
1、概念:是所有类的父类,简称祖宗类。倘若一个类没有继承父类,其实是隐含继承了Object类。
(也就是说,所有的类都有Object类的成员方法)
2、Object类的toString()方法
(1)功能:返回对象的字符串表示:包名.类名@地址
(2)关于toString():
a.打印对象,其实就是打印对象toString方法的结果
Person p1 = new Person("菜虚?", 18);
// 打印对象,其实就是打印对象toString方法的结果
System.out.println(p1); //未重写前: com.itheima.demo15toString方法.Person@50cbc42f
System.out.println(p1.toString()); //未重写前: com.itheima.demo15toString方法.Person@50cbc42f
b.Arraylist类重写了toString()方法
c.系统重写toString(),会打印出该对象的成员变量(系统重写快捷键:Alt + insert ----> toString())
ArrayList<Integer> list = new ArrayList<>();
list.add(11);
list.add(22);
list.add(33);
System.out.println(list);//[11, 22, 33]
System.out.println(list.toString());//[11, 22, 33]
3、关于equals()方法
(1)功能:默认比较对象的地址,返回布尔类型值
(2)系统重写equals(),功能会发生改变,将会变成比较对象的内容,而不是地址值
6、Objects类
1、概念:Objects是对象的工具类,这个类是JDK1.7提供的,他里面的方法方便我们操作对象
2、Objects类中的equals()方法
static boolean equals(Object a, Object b)如果参数相等返回 true,否则彼返回false。
3、Objects类中的isNull()方法
static boolean isNull(Object obj) 判断对象是否为null,如果是null返回true
public static void main(String[] args) {
Student s1 = new Student("凤姐", 18);
Student s2 = new Student("凤姐", 18);
s1 = null; // null表示没有保存任何对象的地址, null不能去调用方法
if (s1 != null) { // 安全的判断,如果对象s1不为null,才去调用equals方法
boolean b = s1.equals(s2);
System.out.println("b = " + b);
}
// Objects类的eiquals在比较对象前会先判断s1是否为null,相当于上面的代码
System.out.println(Objects.equals(s1, s2));
// static boolean isNull(Object obj) 判断对象是否为null,如果是null返回true
System.out.println(Objects.isNull(s1)); // true
System.out.println(Objects.isNull(s2)); // false
}
未完待续。。
.println("b = " + b);
}
// Objects类的eiquals在比较对象前会先判断s1是否为null,相当于上面的代码
System.out.println(Objects.equals(s1, s2));
// static boolean isNull(Object obj) 判断对象是否为null,如果是null返回true
System.out.println(Objects.isNull(s1)); // true
System.out.println(Objects.isNull(s2)); // false
}
未完待续。。