面向对象
封装
继承
多态
面向对象(封装)
在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的优点
-
- 良好的封装能够减少耦合。
-
- 类内部的结构可以自由修改。
-
- 可以对成员变量进行更精确的控制。
-
- 隐藏信息,实现细节。
包装类之自动装箱和自动拆箱
包装类 包装类对象—>基本数据类型 拆箱 基本数据类型—>包装类对象 装箱 自动装拆箱
public class Wraper {
public static void main(String[] args) {
// Byte byte
// Short short
// Integer int
// Long long
// Double double
// Float float
// Character char
// Boolean boolean
Integer a = 10;
int b = a;
int c = 20;
Integer d = c;
Integer e = 127;
Integer f = 127;
Integer h = 128;
Integer i = 128;
int aa = 127;
int bb = 127;
int cc = 128;
int dd = 128;
System.out.println(aa == bb); //true
System.out.println(cc == dd); //true
System.out.println(e == f); //true
System.out.println(h == i); //false
}
}
integer缓存
面向对象(继承)
super
this 调用本类
super 调用父类
子父类实例化顺序
父类的引用指向子类的实例化对象
Persion persion =new Boy();
子类可以拥有自己的方法,父类无法调用
方法的重写
重写:子类对父类中提供的方法进行重新定义
语法:子类和父类中的方法的声明
- 方法重载:在同一个类中 方法参数列表不同的同名方法 这种表现形式我们称之为方法重载
- 方法重写:当父类的方法满足不了子类的需求 子类可以重写父类的方法 这种表现形式我们称之为方法重写
- 二者区别 方法重载是同一个类中 而方法重写必须存在子父类继承关系
向上转型和向下转型
Persion 父类 Boy 子类
```bash
public void test02() {
// 父类的引用指向子类的实例化对象 向上转型 向上转型自动转
Person person = new Boy("面向对象", 1, 40);
person.eat();
// person.work();
//向下转型 注意 只有该对象本身就是子类类型的时候向下转型才会成功
Boy boy = (Boy) person;
boy.eat();
boy.work();
//父类的引用指向子类的实例化对象 向上转型 向上转型自动转
Persion persion = (Persion)new boy
//向下转型 注意 只有该对象本身就是子类类型的时候向下转型才会成功
Boy boy =(boy) persion
instanceof关键字
强制向下转型有风险,可能发生类型转换异常的问题,可以使用instanceof关键字,先判断需要被转换的变量或对象是否属于目标类型,然后再进行强制,更安全。
Animal animal;
animal = new Cat();
if(animal instanceof Cat){//判断animal的运行时类型是否属于Cat类型
Cat cat = (Cat)animal;
cat.catchMouse();//调用Cat特有方法
}
虚方法的理解
虚方法指的是可以被重写的方法,多态形式下,虚方法的调用原则:
- 静态分配:编译在父类中找到最匹配(兼容)的方法
- 动态绑定:运行时执行之前找到的最匹配的方法的重写方法
final
- final修饰的变量是常量
- final修饰的类无法被继承
- *final修饰的方法无法被重写
匿名内部类
public class day10{
public void innerRun() {
new Object(){
public void run(){
System.out.println("加油吧少年");
}
}.run();
}
}
面向对象(多态)
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,
多态性是对象多种表现形式的体现。
现实中中,说人喜欢娱乐
- 电子产品
- 电子竞技
- 追剧
- 运动
多态优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象
多态的实现方式
方式一:重写与重载
Java 重写(Override)与重载(Overload)。
方式二:抽象类和抽象方法
抽象方法 使用abstract修饰,且没有方法体的方法我们称之为抽象方法
- 使用abstract修饰的 类 我们称之为抽象类
- 注:具有抽象方法的类一定是抽象类,但抽象类不一定有抽象方法
- 子类继承父类,要么必须重写父类中的抽象方法,要不子类也是抽象类
- 抽象类不能被实例化
方式三:接口
- 接口也不能被实例化
- 可以多继承
- 可以实现多个接口
接口中使用default 和static 修饰方法
- 在接口中的方法为抽象方法 不允许出现方法体
- 但是从java8中就开始允许接口中的方法有方法体,但必须使用 default 和static修饰
- 在接口中static修饰的方法只能使用接口名点方法名的方式调用不能使用实现类的实例化调用 接口.方法名
- 不可以被子接口继承
- 在接口中default修饰的方法只能使用实现类的实例化对象调用
- 可以被子接口继承
- 可以被子接口重写
- 可以被子接口实现类重写
接口中的静态常量
- 接口里面成员变量必须有初始值
- 接口中的成员变量为静态常量 不能有变量
- 接口中的常量只能通过接口名点的方式调用
函数式接口
- 当接口中只有一个抽象方法的时候我们称这个接口为函数式接口
函数式接口与lambda表达式
- 可以使用FunctionalInterface 注解修饰但不是必须的
- 区别:使用注解修饰的接口的函数式接口 会增加校验
预置函数式接口
public class FunctionINterfaceTest {
@Test
public void test01(){
//没有参数有返回值的
Supplier<String> supplier=()->{
return "大好河山";
};
String slogan =supplier.get();
System.out.println(slogan);
}
@Test
public void test02(){
//一个参数有返回值
UnaryOperator<Integer> unaryOperator=(num)->{
return 2*num+1;
};
Integer apply =unaryOperator.apply(2);
System.out.println(apply);
}
@Test
public void test03(){
//两个参数有返回值
BinaryOperator<Integer> binaryOperator=(x,y)->{
return x+y;
};
Integer apply=binaryOperator.apply(10,20);
System.out.println(apply);
}
@Test
public void test04(){
//一个参数没有返回值
Consumer<String> consumer=(name)-> System.out.println(name);
consumer.accept("王鹏飞");
}
@Test
public void test05() {
// 数据库中的员工
Emp[] emps = new Emp[5];
for (int i = 0; i < emps.length; i++) {
emps[i] = new Emp("emp" + (i + 1), "123456", "emp" + (i + 1));
}
// 登录页面录入账号密码
Emp login = new Emp("emp3", "123456");
// 一个参数一个返回值
Function<Emp, EmpVo> function = (emp) -> {
for (Emp db : emps) {
if (db.getAccount().equals(emp.getAccount()) && db.getPassword().equals(emp.getPassword())) {
return new EmpVo(db.getAccount(), db.getPassword(), db.getNickname());
}
}
return null;
};
EmpVo empVo = function.apply(login);
if (empVo == null) {
System.out.println("账号或者密码错误");
} else {
System.out.println("员工 " + empVo.getNickname() + " 登录");
}
}
@Test
public void test06() {
// 楼市价格
int price = 4000;
if (price == 6000) {
System.out.println("预测楼市价格成功");
} else {
System.out.println("预测楼市失败");
}
}
@Test
public void test07() {
// 楼市价格
int price = 4000;
try {
assert price == 6000;
System.out.println("预测楼市价格成功");
} catch (AssertionError e) {
System.out.println("预测楼市失败");
}
}
@Test
public void test08() {
// 数据库中的员工
Emp[] emps = new Emp[5];
for (int i = 0; i < emps.length; i++) {
emps[i] = new Emp("emp" + (i + 1), "123456", "emp" + (i + 1));
}
// 登录页面录入账号密码
Emp login = new Emp("emp3", "12356");
// 返回布尔值 方法为test
Predicate<Emp> predicate = (emp) -> {
for (Emp db : emps) {
if (db.getAccount().equals(emp.getAccount()) && db.getPassword().equals(emp.getPassword())) {
return true;
}
}
return false;
};
boolean test = predicate.test(login);
if (test){
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
}
}
方法冲突
父类class 和 子类interface
类的优先级要高于接口的优先级
所以调用的都是父类的方法
父类
public class Super {
public static void staticFunction(){
System.out.println("1 super station staticFunction");
}
public void function(){
System.out.println("2 super function");
}
}
子类
public class Sub extends Super implements InterFace{
}
接口
public interface InterFace {
public static void staticFunction(){
System.out.println("3 Interface staticFunction");
}
default void function(){
System.out.println("4 Interface function");
}
}
测试类
public class SubTest {
@Test
public void test01(){
Sub.staticFunction(); // 1
Super.staticFunction(); //1
//1
InterFace interFace=new Sub();
interFace.function();
// 2
Sub sub =new Sub();
sub.function();
}
}