本周我们接触了三大特性
何为三大特性
- 封装
- 继承
- 多态
- 封装是将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问,保护数据的安全。
- 继承是子类拥有父类的所有属性和方法(除了private修饰的属性不能拥有),从而实现了实现代码的复用;
- 多态是使用父类引用接受,不同的子类的对象实例,父类引用调用相同的方法,根据子类不同的实例,产生不同的结果
封装
尽可能隐藏对象的内部实现细节,控制对象的修改及访问的权限。
使用访问修饰符将属性私有,仅本类可见。
- 使用
在公共的访问方法内部,添加逻辑判断,进而过滤掉非法数据,以保证数据安全。
public class Student {
//私有属性,本类可见,其他位置不可见
private int age;
private String sex;
private String name;
public int getAge() {
return age;
}
//getxx(),setxx()方法封装
//过滤掉非法数据
public void setAge(int age) {
if (age>0&&age<150) {
this.age = age;//对非法数据进行判断何过滤
}else {
this.age=18;
}
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 注意
对于私有属性的访问,可通过get/set方法对其访问
继承
- 何为继承
程序中的继承,是类与类之间特征和行为的一种赠与或获得。
两个类之间的继承关系,必须满足“is a”的关系
从我们们生活中的例子延伸:有很多继承的例子
- 父子之间的继承
- 狗是一种动物、狗是一种生物、狗是一种物质。
- 但在Java中,子类继承只能单继承但可以多级继承,例如:狗继承动物,动物继承生物,生物继承物质
继承关键字:extends
继承实例:
- 先写一个Animal父类
public class Animal {
//父类私有属性
private String name,type,sex,color;
private int age;
//动物类叫的方法
public void yell(){
System.out.println("--");
}
//动物父类睡觉的方法
public void sleep() {
System.out.println("趴着睡");
}
public void eat() {
System.out.println("+++++");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
- 狗继承父类
public class Dog extends Animal{
public void yell(){
System.out.println("汪汪叫");
}
//狗子类重写父类的吃
@Override
public void eat() {
System.out.println("啃骨头");
}
}
这个例子用到了方法的重写,那么我们来复习重写
- 为什么要重写
因为虽然子类可以继承父类的方法,但父类提供的方法无法满足子类需求时,可在子类中定义和父类相同的方法进行重写 - 重写规则
方法名和参数列表和父类相同
返回值类型和父类相同
访问修饰符可和父类相同或者更加宽泛,
例如父类为protected保护类,而子类可使用protected或public
- 重写和重载的区别
二者仅仅一字之差,但却区别很大
重载、重写都有一个相同点:方法名相同
区别:重载方法的参数个数类型顺序的不同都可以构成重载,和访问修饰符、返回值无关
重写方法
public class Test {
public static void main(String[] args) {
A a=new A();
/*
* 构造函数是创建对象时用来给变量赋值的
* 例如:public A(int age)
* A a=new A(22)
* 而a.A();是错的
* */
a.Test1();
a.sleep();
A a2=new A(20);
}
}
class A extends SuperTest{
int age=22;
public void Test1() {
System.out.println(this.age);
//调用父类的属性
System.out.println(super.age);
}
public void sleep() {
super.sleep();
}
//在子类里面调用父类的有参构造函数
public A(int age) {
super("子类");
}
/*super()表示调用父类中的构造方法
1、子类继承父类,子类的构造方法的第一行,系统会默认编写super(),在调用子类的构造方法时,先调用父类的无参数构造方法
2、如果父类中只有有参数构造方法,那么子类继承父类时会报错,因为子类的构造方法在默认调用父类无参数构造方法super()不存在。
3.如果子类的第一行编写了this()、this(实参),因为this()也会占用第一行,所以此时就会将super()挤掉,就不会调用父类构造方法。
*/
//在子类里面调用父类的无参构造函数
public A() {
super();
}
}
多态
- 多态性的理解
可以理解为一个十五的多种形态,就比如一个人在不同人角度看是具有不同的形态,在老师眼中是个学生,在父母眼中是个孩子…但他终究是属于一个个体是一个人。
- 何为多态性:
在Java中是指:父类的引用指向子类的对象,或者说子类的对象赋给父类使用 - 多态性的举例
1.先定义一个父类
public class Animal {
String name,type,sex,color;
public void yell() {
System.out.println("叫");
}
public void sleep(){
System.out.println("睡睡睡");
}
public void eat(){
}
}
2.构建子类
public class Cat extends Animal {
public void yell() {
System.out.println("喵喵喵");
//super.yell();
}
public void sleep() {
System.out.println("趴着睡");
}
@Override
public void eat() {
System.out.println("吃猫粮中......");
}
}
public class Dog extends Animal{
@Override
public void yell() {
System.out.println("汪汪汪");
//super.yell();
}
public void sleep() {
System.out.println("趴着睡");
}
@Override
//方法重写
public void eat() {
System.out.println("吃狗粮中.....");
}
}
3.父类作为形参传入
public class Master {
//父类作为形参
public void feed(Animal animal) {
System.out.println("第一次喂食");
animal.eat();
}
}
Master m=new Master();
Dog dog=new Dog();
m.feed(dog);//子类对象作为实参传值,实际上就是Animal animal=new Dog()
/*
也可以是Animal animal=new Dog();m.feed(animal),也可以达到同样的效果
*/
- 向上转,向下转
1.向上转型:为多态,即父类的引用指向子类的对象;
例如Animal animal=new Dog();
这就是向上转,子类转向父类;
2.向下转型:将父类引用中的真实子类对象,强转回子类本身类型,称为向下转型,类似于变量的强制转型。
注意:Animal animal=new Dog();Dog dog1=(Dog) animal;
这就相当于向下转从父类转回子类,这样可以调用子类的方法。
Dog dog=new Dog()
直接new对象,二者区别,直接调用不需要继承父类,既然这样为什么不直接new对象就好。原因就出在于继承,我继承父类的东西,而且使用多态向上转了,但这时我又想使用子类的东西,这样向下转型就要使用了。直接实例化对象是不需要继承父类的,也可以使用对象的属性和方法。
- instanceof 关键字
向下转型前,应判断引用中的对象真实类型,保证类型转换的正确性。
语法:父类引用 instance of 类型 //返回boolean类型结果
注意
a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
如果 a instanceof A返回true,则 a instanceof B也返回true.其中,类B是类A的父类。
实例
//因为不清楚顾客会挑选那一只动物,所以用instanceof判断
if (animal instanceof Dog) {
Dog dog=(Dog) animal;
dog.yell();//如果dog是Dog类的实例则调用yell方法
多态的两种使用场景
1.多态作为返回值类型:
public Animal Sell(int num) {
Animal animal=null;
if (num==1) {
animal=new Cat();
}else if (num==2) {
animal=new Dog();
}else if (num==3) {
animal=new Snake();
}else if(num==4){
animal=new Fish();
}else {
System.out.println("输入错误!");
}
return animal;
}
2.多态作为形参:
public void func(Animal animal){//Animal animal = new Dog();
animal.eat();
animal.shout();
}
三个关键字
- abstract
- static
- final
abstract抽象
- 何为抽象:
似是而非的,像却又不是;具备某种对象的特征,但不完整
- 抽象类、抽象方法:
1.抽象类
被abstract修饰类,无法独立存在,此类不能new对象,即不可实例化。
被abstract修饰的类,称为抽象类。
抽象类意为不够完整的类、不够具体的类。抽象类中一定有构造器,便于子类实例化时调用。抽象类,一般都用于继承。
2.abstract修饰方法:抽象方法
抽象方法只方法的声明,没方法体;void get();
直接加分号结束,不需要大括号的方法体;
包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的,抽象类不一定有抽象方法
若子类重写了父类中的所的抽象方法后,此子类方可实例化
若子类没重写父类中的所的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
注意
1.abstract不能用来修饰:属性、构造器等结构
2.abstract不能用来修饰私方法、静态方法、final的方法、final的类
static静态
何为静态:
- 静态(static)可以修饰属性和方法。
- 称为静态属性(类属性)、静态方法(类方法)。
- 静态成员是全类所有对象共享的成员。
- 在全类中只有一份,不因创建多个对象而产生多份。
- 不必创建对象,可直接通过类名访问。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
说明:
① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
② 静态变量的加载要早于对象的创建。
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
final 最终的
1.可以用来修饰:类、方法、变量
2.1 final 用来修饰一个类:此类不能被其他类所继承。
-
比如:String类、System类、StringBuffer类
2.2 final 用来修饰方法:表明此方法不可以被重写
-
比如:Object类中getClass();
2.3 final 用来修饰变量:此时的"变量"就称为是一个常量
- final修饰属性:可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化
- final修饰局部变量:
-
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
接口(重点)
- 概念:
接口相当于特殊的抽象类,定义方式、组成部分与抽象类类似。使用interface关键字定义接口。
- 特点:
没有构造函数,不能创建对象。
只能定义:公开静态常量、公开抽象方法。
实例:
public interface MyInterface {
//公开的静态常量
//public static final String NAME="接口1";
String NAME="接口1";
//公开的抽象方法
//public abstract void method1();
void method();
}
实现类:
public class Impl implements MyInterface1{
@Override
public void method() {
System.out.println("method");
}
}
注意
1.接口使用上也满足多态性
2.接口,实际上就是定义了一种规范
3.开发中,体会面向接口编程!
4.接口中不能定义构造器的!意味着接口不可以实例化
Java开发中,接口通过让类去实现(implements)的方式来使用.
如果实现类覆盖了接口中的所抽象方法,则此实现类就可以实例化
如果实现类没覆盖接口中所的抽象方法,则此实现类仍为一个抽象类
Java类可以实现多个接口 —>弥补了Java单继承性的局限性
接口与接口之间可以继承,而且可以多继承
- 接口规范
任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
实现接口中的抽象方法时,访问修饰符必须是public。
同父类一样,接口也可声明为引用,并指向实现类对象。
public class TestPerson2 {
public static void main(String[] args) {
Flyable flyable=new Person("小张",22);
flyable.fly();
Fireable fireable=new Person("小李", 15);
fireable.fire();
}
}
- 接口实现多态
接口实现多态:使用接口作为方法的参数和返回值,实际赋值实现类对象实现多态。
定义接口
public interface Runnable{
//跑
void run();
}
父类
public abstract class Animal {
public void eat() {
System.out.println("吃");
}
public void sleep() {
System.out.println("睡");
}
}
实现类
public class Dog extends Animal implements Runnable,Swimable{
public void shout() {
System.out.println("狗狗开始叫...");
}
@Override
public void swim() {
System.out.println("狗狗游泳...");
}
@Override
public void run() {
System.out.println("狗狗跑步...");
}
}
- 宏观接口,接口回调
宏观概念:接口是一种标准、规范。
接口回调:先有接口的使用者,后有接口的实现者。
- 接口的好处:
程序的耦合度降低。
更自然的使用多态。
设计与实现完全分离。
更容易搭建程序框架
更容易更换具体实现。
课堂问题
- java有多少种方法获取一个对象的实例
new对象
反射机制
调用对象的clone()方法
反序列化
- 访问修饰符,除了属性,还能用在什么地方
可以修饰方法和类
- 为什么不能直接输出super
从规范上来说,super永远不可能作为单独的表达式,后面必须加上后缀