继承
8.1继承
**总结一句:**把多个事物中重复性的内容进行抽取,并生成另外一个类,该类就是其他类父类,其他
类称之为子类,父类与子类之间用extends关键字来标明
继承的好处:
继承的出现提高了代码的复用性
继承的出现让类与类之间产生关系,也为我们后面多态提供了前提
单继承与多继承
在现实生活中,父与子一对多关系,子与父一对一
使用继承时,除了要考虑类与类之间重复的内容之外,更重要的是去考虑关系,必须是一种 is a 关
系
即XXX是YYY的一种!苹果是水果的一种,狗是动物的一种
Java中 类与类之间只能支持单继承, 接口与接口之间可以支持多继承
定义: 继承就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为
class B{
……
}
}
class A extends B{
……
}
}
子父类中,成员变量的特点
子类没有,父类有且非私有,子类对象能获取父类的属性
子类没有,父类有且私有,子类对象不能获取父类的属性
子类有,父类有且非私有,子类对象获取的是子类的属性,不存在重写的概念
子类有,父类没有, 子类对象获取的是子类的属性
如果子类中,成员变量 和 父类变量 和局部变量重名时,在子类的方法中首先获取的是子类中的局部变量,使用this来获取子类的成员变量,使用super来获取父类空间中的父类变量。
public class Sample {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.num);
zi.show();
}
}
class Fu {
int num = 10;
}
//父类 超类 基类
class Zi extends Fu {
int num = 20;
void show() {
int num = 30;
System.out.println(num + "," + this.num + "," + super.num);
}
}
子父类中,构造函数的特点
构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。
小结:
每一个类中的构造函数第一句如果不是 this()调用本类中其他构造函数的话,默认第一句是隐藏的 super()
当创建子类对象时,在子类的构造函数执行之前,父类的构造函数先执行,是因为在创建子类对象的时候,需要父类为继承给子类的一些数据进行初始化
public class Sample {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
class Fu {
int num;
Fu() {
System.out.println("Fu show..." + num);
num = 4;
}
}
class Zi extends Fu {
Zi() {
super(); //调用父类的无参构造函数 默认是隐藏的
//父类的构造函数一旦执行完毕 则紧接着执行子类成员变量的显示初始化
System.out.println("Zi show..." + num);
}
}
/*
结果:
Fu show...0
Zi show...4
*/
this()与super()是否冲突
如果子类的多个构造函数们之间没有调用关系,则每一个子类的构造函数第一句都是 super(),即子类的多个构造函数都是先调用父类的构造函数对父类的数据进行初始化。
子类中有 多个构造函数,且存在构造函数之间的调用关系,即构造函数的第一句为this(参数列表),在使用该构造函数创建对象时会调用该类的其他构造函数来调用父类的构造函数。
public class Sample {
public static void main(String[] args) {
Zi zi1 = new Zi();
Zi zi2 = new Zi(1);
Zi zi3 = new Zi(1,2);
}
}
class Fu {
int num;
Fu() {
System.out.println("Fu show...");
}
}
class Zi extends Fu {
Zi() {
this(1);
System.out.println("Zi show ... 0");
}
Zi(int a) {
this(1,2);
System.out.println("Zi show ... 1");
}
Zi(int a , int b) {
super();
System.out.println("Zi show ... 2");
}
}
/*
结果:
Fu show...
Zi show ... 2
Zi show ... 1
Zi show ... 0
Fu show...
Zi show ... 2
Zi show ... 1
Fu show...
Zi show ... 2
*/
小结:
在构造函数中,第一句要么是this(),要么是super()
不存在每一个构造函数第一句都是this(),否则递归调用
存在每一个构造函数第一句都是super(),构造函数之间不调用
this()与super()本身不冲突的,如果构造函数之间有调用关系,那么最后一个被调用的构造函数就不能再回调,那么其第一句就不能是this(),只能是super()
如果父类中,没有无参构造函数的存在,只有有参数的构造函数的话,那么子类中默认的super() 就调用不到父类无参构造函数!引发错误!
子父类中,成员函数的特点
如果父类有,子类没有,调用的是父类的
如果父类没有,子类有,调用的是子类的
如果父类有,子类也有,调用的是子类的
如果父类有,但是为私有,则子类继承不到,除非子类自己写一个
上述第三个情况,我们称之为是函数的重写/覆盖/Override
重写的作用:严格意义上而言,子类并非是父类的一个子集。子类的内容很大程度上,很多情况下,都是父类的一种扩展或增量,重写仅仅去保留了父类的功能声明,但是具体的功能内容由子类来决定!
重写的规则:
重写的时候,子类的权限必须大于等于父类的权限,否则编译时报错
重写的时候,返回值不能更改,否则编译时报错
public class Sample {
public static void main(String[] args) {
Zi zi = new Zi();
zi.showC(10);
zi.showC(10,20);
}
}
//public > 默认 > protected > private
class Fu {
public void show(){
System.out.println("Fu show...");
}
public int showB() {
return -1;
}
public void showC(int a){
System.out.println("Fu showC...");
}
}
class Zi extends Fu {
void show() {
System.out.println("Zi show...");
}
public void showB() {
}
public void showC(int a,int b){
System.out.println("Zi showC....");
}
}
8.2 final关键字
final:
用于修饰不可改变内容,可以用于修饰类、函数和变量。
类:被修饰的类,不能被继承
函数:被修饰的方法,不能被重写
变量:被修饰的变量,不能被重新赋值
final修饰变量
表示该变量的值不可被改变
变量主要分为两种,基本数据类型、引用数据类型的变量
基本类型的局部变量,被final修饰后,表示变量所存储的常量值不能改变,只能赋值一次
引用数据类型的变量,被final修饰后,只能指向一个对象,地址不能再更改。但是不影响对象内部的成员变量值的修改
一般而言,当我们在定义常量(用变量名+final来表示),并定义成静态变量
public static final 数据类型 变量名 = 常量数据;
对于常量的变量名起名规则为 全部单词大写 单词与单词之间用下划线分隔
public static final int MAX_VALUE = 100;
final修饰函数
如果某一个类中的函数,不想让其子类去重写的话,该函数就可以声明为final类型
final修饰类
表示该类不能被继承
8.3 抽象类
概述:
父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。
定义:
抽象方法:没有方法体的方法
抽象类:包含抽象方法的类
抽象方法
使用 abstract关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。
定义格式:
修饰符 abstract 返回值类型 方法名 (参数列表);
抽象类
如果一个类包含抽象方法,那么该类必须是抽象类。
定义格式:
public abstract class Animal {
public abstract void run();
}
抽象方法:
当我们将多个事物的共同行为(方法)进行抽取并封装到另外一个类中时,发现在该类中,这些方法的具体执行内容无法确定,只能由这些子类来决定该方法的具体执行,那么在该类中,将这些抽取来的方法仅保留方法声明,但不保留方法体即可,那么该方法就是抽象方法,用abstract关键字来修饰,既然有了抽象方法的存在,那么具有抽象方法的类也被称之为抽象类,也必须用abstract修饰。抽象类不能创建对象,只有其实现子类能够创建对象。
抽象类的特点:
抽象类和抽象函数都需要被abstract修饰,抽象方法一定在抽象类中
抽象类不能创建对象,因为如果一旦创建对象,在调用其函数时,函数没有具体执行内容
只有覆盖了抽象类中所有的抽象函数后,子类才可以实例化。否则,该子类还是一个抽象类
抽象类的细节问题:
抽象类一定是一个父类,因为抽象类本身就是有多个事物进行抽取而来的
抽象类有成员变量、成员函数、构造函数,抽象类与一般类唯一的区别就是抽象类中抽象函数,其他一律相同(抽象类不能创建对象)
抽象类比一般类可以多定义一个成员:抽象函数
一般类可以创建对象,而抽象类不能创建对象
有抽象函数的类一定是抽象类,抽象类不一定有抽象函数!
抽象关键字abstract不能与以下关键字共存
final:final修饰类,表示该类不能被继承;final修饰函数时,表示函数不能被重写;不能与absteact共存,抽象类本就是父类,并且其中的抽象函数就等着被子类重写。
private:private修饰函数,表示函数被私有,不能被子类继承;不能与absteact共存,抽象函数就等着被子类重写。
static:static修饰的函数,属于类的,随着类的加载从而被加载方法区中,和对象没有关系了,可以直接用类来调用静态成员,如果抽象函数被静态修饰,被类调用时没意义。
8.4 接口
概述:
接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。
当一个抽象类中,所有的方法都是抽象函数时,那么,该类就可以用接口来表示
接口不是一个类了,一些类的功能和操作不再适用于接口
接口中没有成员函数,没有成员变量,没有构造函数,没静态函数,没有静态变量
接口也不能直接去创建对象
接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。
引用数据类型:数组,类,接口。
接口的使用,它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
接口中的变量和函数就会有一些特殊的含义
接口中的变量 默认是公共静态常量 public static final类型 就算不写这些关键字 也是默认的
接口中的函数 默认是公共抽象的函数 public abstract 类型 就算不写这些关键字 也是默认的
默认方法的使用
一个接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须重写一次。
接口中的默认方法可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。
继承默认方法,代码如下:
定义接口:
public interface LiveAble {
public default void fly(){
System.out.println("天上飞");
}
}
定义实现类:
public class Animal implements LiveAble {
// 继承,什么都不用写,直接调用
}
定义测试类:
public class InterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
Animal a = new Animal();
// 调用默认方法
a.fly();
}
}
/*
输出结果:
天上飞
*/
重写默认方法,代码如下:
定义接口:
public interface LiveAble {
public default void fly(){
System.out.println("天上飞");
}
}
定义实现类:
public class Animal implements LiveAble {
@Override
public void fly() {
System.out.println("自由自在的飞");
}
}
定义测试类:
public class InterfaceDemo {
public static void main(String[] args) {
// 创建子类对象
Animal a = new Animal();
// 调用重写方法
a.fly();
}
}
/*
输出结果:
自由自在的飞
*/
静态方法的使用
接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用,代码如下:
定义接口:
public interface LiveAble {
public static void run(){
System.out.println("跑起来~~~");
}
}
定义实现类:
public class Animal implements LiveAble {
// 无法重写静态方法
}
定义测试类:
public class InterfaceDemo {
public static void main(String[] args) {
// Animal.run(); // 【错误】无法继承方法,也无法调用
LiveAble.run(); //接口的静态方法使用接口名来调用接口中的静态方法
}
}
/*
输出结果:
跑起来~~~
*/
私有方法的使用
私有方法:只有默认方法可以调用
私有静态方法:默认方法和静态方法可以调用
如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。
public interface LiveAble {
default void func(){
//默认方法可以调用接口中的私有方法和静态的私有方法
func1();
func2();
}
private void func1(){
System.out.println("跑起来~~~");
}
private void func2(){
System.out.println("跑起来~~~");
}
}
优先级的问题
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法。代码如下:
interface A {
public default void methodA(){
System.out.println("AAAAAAAAAAAA");
}
}
class D {
public void methodA(){
System.out.println("DDDDDDDDDDDD");
}
}
class C extends D implements A {
// 未重写methodA方法
}
public class Test {
public static void main(String[] args) {
C c = new C();
c.methodA();
}
}
/*
输出结果:
DDDDDDDDDDDD
*/
接口与类、接口之间的关系
类与类之间是单继承关系,类与接口之间是多实现关系,接口与接口之间是多继承关系
类与接口之间的实现关系用implements关键字表示,可以实现多个接口,但是类要么实现接口中的所有方法,如果抽象方法有重名的,只需要重写一次,要么这个类声明为abstract
接口与接口有着多继承的关系,对于一个子类接口(继承了其他接口的方法)的实现子类(接口的实现类)而言,要么把这几个接口全部实现,要么声明为abstract,如果父接口中的默认方法有重名的,那么子接口需要重写一次
接口与接口之间不存在实现的关系
子接口重写默认方法时,default关键字可以保留。
子类重写默认方法时,default关键字不可以保留。
接口中的特点总结
接口中的变量都是全局静态常量
接口中的方法都是全局抽象函数
接口含有默认方法和静态方法(JDK 8)
接口含有私有方法和私有静态方法(JDK 9)
接口中,没有构造方法,不能创建对象
接口中,没有静态代码块
子类必须覆盖接口中所有的抽象方法,或声明为abstract
类与接口之间可以存在多实现关系
接口与接口之间可以存在多继承关系
类与类之间只能是单继承关系
接口与抽象类的区别
相同点:
都位于继承或实现的顶端
都不能实例化
都包含抽象函数,其子类都必须覆盖这些方法
不同点:
一个类只能继承一个父类,但是可以实现多个接口
抽象类中其实可以存在一些已经实现好的方法,有部分未实现的方法由子类来决定;接口中只能包含抽象函数,子类必须完全实现
8.5 多态
概述:
多态是继封装、继承之后,面向对象的第三大特性。
生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
8.5.1 多态的定义
定义:是指同一行为,具有多个不同表现形式
8.5.2 实现多态的前提
继承或者实现【二选一】
方法的重写【意义体现:不重写,无意义】
父类引用指向子类对象【格式体现】
8.5.3 多态的体现
多态体现的格式:
父类类型 变量名 = new 子类对象;
变量名.方法名();
父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
Fu f = new Zi();
f.method();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。
代码如下:
public abstract class Animal {
public abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
public class Test {
public static void main(String[] args) {
//多态形式,创建对象,向上转型
Animal cat = new Cat();
//先找父类中是否有eat()这个方法,没有编译报错,有的话调用子类中定义的方法体
cat.eat();
Animal dog = new Dog();
dog.eat();
}
}
8.5.4 多态的好处
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。
public abstract class Animal {
public abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Cat c = new Cat();
Dog d = new Dog();
// 调用showCatEat
showCatEat(c);
// 调用showDogEat
showDogEat(d);
/*
以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代
而执行效果一致
*/
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
优点:
面向父类/接口编程、关注的是父类/接口的能力、忽略了子类类型、可以使程序编写的更简单,并有良好的扩展。
缺点:
无法使用子类特有的属性和方法。
8.5.3 引用类型转换
8.5.3.1 向上转型
向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
当父类引用指向一个子类对象时,便是向上转型,向上转型后,该类只可以使用父类中声明的方法,但调用的是子类中重写父类的方法,不可以调用子类中自己定义的方法。
父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();
8.5.3.2 向下转型
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型,向下转型后可以调用子类中定义的方法。
子类类型 变量名 = (子类类型) 父类变量名;
如:Cat c =(Cat) a;
为什么用转型
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void watchHouse() {
System.out.println("看家");
}
}
public class Test {
public static void main(String[] args) {
// 向上转型,只能调用父类中定义的方法,不可以调用子类中定义的方法
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
}
}
转型的异常
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
}
}
这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。
为了避免ClassCastException的发生,Java提供了 instanceof关键字,给引用变量做类型的校验,格式如下:
变量名 instanceof 数据类型
如果变量属于该数据类型,返回true。
如果变量不属于该数据类型,返回false。
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}
8.6 内部类
8.6.1 概述
定义:将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
8.6.2 成员内部类
成员内部类 :定义在类中方法外的类。
class 外部类 {
class 内部类{
}
}
在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类 Car 中包含发动机类Engine,这时, Engine 就可以使用内部类来描述,定义在成员位置。
class Car { //外部类
class Engine { //内部类
}
}
8.6.3 访问特点
内部类可以直接访问外部类的成员,包括私有成员
外部类要访问内部类的成员,必须要建立内部类的对象
创建内部类对象格式:
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
外部类名.内部类名 对象名 = new 外部类型.内部类型();
Outter.InnerB b=new Outter().new InnerB();
Outter.InnerB b=new Outter.InnerB();
public class Person {
private boolean live = true;
class Heart {
public void jump() {
// 直接访问外部类成员
if (live) {
System.out.println("心脏在跳动");
} else {
System.out.println("心脏不跳了");
}
}
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
}
public class InnerDemo {
public static void main(String[] args) {
// 创建外部类对象
Person p = new Person();
// 创建内部类对象
Heart heart = p.new Heart();
// 调用内部类方法
heart.jump();
// 调用外部类方法
p.setLive(false);
// 调用内部类方法
heart.jump();
}
}
/*
输出结果:
心脏在跳动
心脏不跳了
*/
内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
比如,Person$Heart.class
8.6.4 匿名内部类
匿名内部类 :是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作:
定义子类
重写接口中的方法
创建子类对象
调用重写后的方法
而匿名内部类可以简化上面的方法,为我们调用方法提供快捷的方式。
前提
匿名内部类必须继承一个父类或者实现一个父接口。
格式
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
举例
public abstract class FlyAble{
public abstract void fly();
}
public class InnerDemo {
public static void main(String[] args) {
/*
1.等号右边:是匿名内部类,定义并创建该接口的子类对象
2.等号左边:是多态赋值,接口类型引用指向子类对象
*/
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飞了~~~");
}
};
//调用 fly方法,执行重写后的方法
f.fly();
}
}
通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:
public class InnerDemo2 {
public static void main(String[] args) {
/*
1.等号右边:定义并创建该接口的子类对象
2.等号左边:是多态,接口类型引用指向子类对象
*/
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飞了~~~");
}
};
// 将f传递给showFly方法中
showFly(f);
}
public static void showFly(FlyAble f) {
f.fly();
}
}
以上两步,也可以简化为一步,代码如下:
public class InnerDemo3 {
public static void main(String[] args) {
/*
创建匿名内部类,直接传递给showFly(FlyAble f)
*/
showFly( new FlyAble(){
public void fly() {
System.out.println("我飞了~~~");
}
});
}
public static void showFly(FlyAble f) {
f.fly();
}
}
8.7 包与权限
8.7.1 包
定义: 包其实相当于操作系统的文件夹
好处:管理java文件的:方便寻找(包名+类名)、解决重名的问题
保护资源 (结合着访问控制符,来限定资源的访问)
8.7.1.1 包的使用
定义包名:
一般都用小写英文
见名之义 公司域名的倒写+ 【部门名称】+项目名称+模块 、用.分隔,不能以.开头
包的声明:
package com.openlab.student.entity;
必须位于类的第一行非注释语句
包的导入:
import java.util.Scanner;:类的完全限定名
import java.util.*;:导入util包下的所有java类,但是不会导入子包中的类
导入的类重名,来自不同的包,需要显式的写出
8.7.2 权限
8.7.2.1 概述
在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限。
public:公共的
protected:受保护的
default:默认的
private:私有的
权限:
public 共有的 类内部、同包、不同包
protected 受保护的 类内部、同包、不同包的子类
default 默认的 类内部、同包
private 私有的 类内部(ok) 同包(否) 不同包(否)
public>protected>default>private
8.9 枚举
enum 可以当成数据类型来用
管理一系列的常量(限定取值)
由来: 枚举出来之前都是拿class或者interface来组织管理常量—基本的数据类型
缺点: 只要数据类型合适,就会编译通过,不考虑实际的业务,可能造成错误
enum 限定取值
本质是Enum的子类:不能再继承别的类
public final String name() {
return name;
}
public final int ordinal() {//序号
return ordinal;
}
自定义枚举
public enum Role2 {
ROLE_NOMAL,
ROLE_VIP,
ROLE_SUPER_VIP
}
//可以当成数据类型来用
private Role2 role;
限定取值
user.setRole(Role2.ROLE_NOMAL);
枚举值的比较 equals或者==都可以
Role2 r=user.getRole();
if(r==Role2.ROLE_SUPER_VIP) {
System.out.println("超级用户。。。。。。。。。。。。");
}else if(r==Role2.ROLE_NOMAL) {
System.out.println("普通用户。。。。。。。。。。。。");
}
//用switch更方便
switch(r) {//byte int short String(1.7+),enum
case ROLE_SUPER_VIP:
System.out.println("超级用户。。。。。。。。。。。。");
break;
case ROLE_NOMAL:
System.out.println("普通用户。。。。。。。。。。。。");
break;
case ROLE_VIP:
System.out.println("VIP用户。。。。。。。。。。。。");
break;
}