面向对象的三大特点:
封装;继承;多态
封装:
为了代码安全性;
用private修饰,被修饰的方法和属性只能在本类中使用
封装并不是代表成员变量都不能修改,而是说不能直接拿到这个字段,当属性被private修饰后,可以设置set(),get(),和其他方法来访问成员变量
权限修饰符:
其中default不需要写,没有权限修饰符会默认是default
补充知识:包
为了更好的管理类,把多个类收集在一组,称为软件包;包也可以看作对类和接口进行封装
创建包:在src下new package,包名采用域名倒置法:com.bit.www此事会生成个包,不同包下可以有相同的类,包创建后在硬盘里以文件夹的形式存储。
建立包后,在包下类写代码,类上会有导包的代码 ,包名要和代码路径相匹配,包为com.bit.www后,会将代码存储到com/bit/www路径下。如果没有package语句,那么该类会被给放到默认包里
,
域名会产生三个包(即三个文件夹)展开按钮:
导包:
导入包是为了用包下类中的方法
导包格式
比如想使用Data类
1 完整写:
2 含有通配符*,即这个包下所含有的类都能使用,缺点:util和sql都有一个类叫Data,因此编译器会因为不知道具体调用哪一个而报错,因此最好要导入完整路径
import可以导入包中所有类(包加通配符)或者某个具体类,但是不能只导入某个具体包
除此之外,用import static 可以导入静态方法和字段,因为不常用,所以这里不多赘述。
常见包:
java.lang的包不需要导入
补充知识:static
静态成员变量(不存在静态局部变量):
所有类共享静态成员变量。
被static修饰的属性,不会存处在对象中而是存在方法区,
注,可以通过对象访问静态成员变量,但是不合理,正确写法应该用类名去访问。因为被static修饰的字段属于类,而不属于对象,因此也不依赖于对象,即赋值,调用静态成员变量是不需要创建对象的
当类被加载而创建,类被销毁而销毁
静态方法:
所有对象共享该方法;同理应该用类名调用(在同类中可以不写类名,但是不同类就得写)。
注意:
1.在静态方法中无法直接用本类的成员变量,必须通过对象的引用才能使用;(非静态方法可以)
2.静态方法中不能出现this
补充知识:代码块:
代码块分为静态代码块,普通代码块,实例(构造代码块)
普通代码块:
定义在方法里,用{}括住即可;
实例(构造)代码块:
同普通代码块,只需要用{}括住即可,但是和普通代码块的位置不一样,实例代码块是在类内,方法外的;一般用于初始化非静态变量(也可初始化静态变量)
静态代码块:
即在{}前加一个static,静态变量的初始化是在静态代码块中进行的
static{
不能加this
};
执行顺序:
静态代码块在类加载的时候执行(只执行一次),被JVM开辟空间并进行初始化;构造代码块在创建对象的时候被调用;静态代码块会先于实例代码块执行
总之,静态代码块最先执行,接下来是实例代码块,最后执行构造方法
注意,静态代码块和静态变量就地初始化的先后顺序是看谁写在前就谁先执行,且静态代码块先于普通成员的就地初始化执行
知识点补充:用sout打印对象:toString
打印结果:,前面是包的地址,后面是哈希值
当我们查看原码:查看源码方式,按住ctrl,然后点击方法
因此当子类重写父类的toString方法后,就会调用子类的重写方法,同set,get可以用ideal的快捷键;打印对象的时候不仅会打印出toString的返回值,如果toString里也有sout方法也会打印出来
重写方法:,
运行结果:
继承:
父类对子类共性的提取,提高了代码的复用;(实现多态的基础)
关键词:extends:子类 extends 父类
父类(基类,超类)
子类(派生类)
子类继承父类成员什么
除了父类的构造方法外的所有方法和属性
因为子类继承了父类一定要先帮父类进行初始化——调用父类的构造方法
访问权限:
类的访问权限只有public喝default两种;
当父类属性被protect修饰时:
同包中,创建父子类对象都可以通过父子类的引用调用属性
不同包中,访问父类的protetcted属性或者方法,是不可以通过创建父类对象调用的。只能通过子类对象去引用访问(必须是在子类中)
代码演示
不同包的子类:在子类中通过父类的对象的引用:可知在子类中可以用this,super,直接调用或创建子类的方法调用,但如果用父类对象的引用就会报错
和父类同包:父子类对象的引用都可以
和子类同包:父子类对象的引用都不可以
被private修饰后(只能在本类中访问):
子类能继承,但不能访问
具体其他不是很重要,就不多赘述
总之子类只能访问父类非私有的属性和方法
super
表示从父类继承过来的数据引用,super()表示引用父类的构造方法
不能指向父类的父类
super同this一样不能出现在static方法当中
这里调用了父类有参构造,注意super必须写在第一行,因为this()也必须写在构造方法的第一行,所以只有当子类的构造方法中系统默认调用super()时(父类的无参构造)才能加this().
子类的每个构造方法都必须调用父类中一种构造方法,当父类中有无参构造时系统会默认从父类中调用super()
父类和子类方法,属性重名
子类可以继承父类的属性和方法,如果子类也有相同的属性和方法,那么子类优先使用自己的,没有再访问父类,另外也可以通过super来访问父类;thie优先访问子类的,没有再访问父类的
父类的静态方法和属性也可以被子类继承,但是当父类方法被static,finnal,private 修饰时,子类无法重写
执行顺序
父子类静态代码块,父子类实例代码块,父子类构造方法的代码块。
执行顺序
1父类静态代码块;2子类静态代码块;3父类实例代码块;4父类构造方法的代码块;5子类实例代码块;6子类构造方法的代码块。
静态代码块只会实行一次,因此,当第二次创建对象时,静态代码块不会执行
当main函数在父类当中,因为执行main会加载类,因此会自动执行父类静态代码块(main函数里为空也会执行,因为只要类第一次加载就会执行);
同理若main在子类当中,那么就会执行父子类代码块
例子:思考
结果是:打印子类0
继承特点:
java支持多层继承(但一般不会超过三层),但不支持多继承,即子类只能继承一个父类,因此为了实现多继承,发明了接口
补充知识:final
被final修饰后的变量不能再改变,被称为常量;被final修饰方法后不能被重写,被称为密封法
当类被final修饰后那么该类不能被继承,这个类被称为密封类,
多态:
同一个引用 引用了同一个方法,但因为对象引用的不同,所表现出来的行为不同,我们称之为多态
即如图所示,形参是父类,通过实参传入不同的子类,那么就调用了该子类的方法
运行结果:
补充知识:向上转型
发生多态的条件之一,即父类引用引用了子类对象;
即创建子类对象后,其接收者的类型是其父类;
从而可以调用子类重写父类的方法,注意向上转型不能调用子类特有方法
常见形式:
向下转型:
弥补多态缺点,可以调用子类的特有方法;
关键字instance
判断是否引用的是Dog对象,是的话返回true,否则返回false
animal是父类,大类型转小类型需要强转,但为了防止将传入的Cat类型强转成Dog类型,所以需要instance进行判断
打印结果是 汪汪,因为调用了Dog类中的方法
头一次看会觉得很抽象,为什么要这么写,直接创建子类对象调用子类方法不就好了?
如果我们要写一个函数,不用向下转型的话,那么形参就得设置某一具体类,如果我们想实现猫和狗的特有方法,那么就得写两个函数去分别实现他们的特有方法,但是如果用到向下转型,那函数只需要写一个,无非多写点if而已。
补充知识:重写
子类对父类方法或接口的重写,除了{}中的的代码不一样,方法名,返回类型,参数列表都必须一致
如果当参数返回类型是父子关系的时候,可以不一样
多态为什么当子类重写了父类方法就调用父类方法呢,这是因为动态绑定
被private,static,final修饰后方法不能被重写,构造方法也不能被重写(static是类的方法,重写是某个对象的具体方法,因此被static不能被重写)
子类重写权限不低于父类权限。 子类重写父类方法权限不能低于父类权限:向上转型的权限应该越来越小,而不是变大
注解:
校验作用
补充知识:动态绑定
静态绑定:例如重载,在编译时期,会根据你方法参数的不一样从重载方法中来选定你要使用的方法
动态绑定:即在编译时期无法确认你要是用的方法,例如在向上转型中,调用Animal.eat(),在编译的时候认为你是在调用父类方法,但在运行中会去调用子类的重写方法
理解多态的基础
注意动态绑定是针对方法的属性没有动态绑定;比如子类定义了和父类相同的属性,但是当向上转型后调用该属性,调用的父类属性的值。即调用父类的属性但是在子类中赋值(初始化)
即属性和构造方法没有多态性
构造方法中也会进行动态绑定,不建议在构造方法中调用重写方法
圈复杂度:
就是程序内循环和条件语句出现次数,尽量要降低圈复杂度,而多态就可以降低圈复杂度