目录
一、封装(encapsulation)
什么是封装?举个例子,比如一台电视机,电视机内部有复杂的各种器械,而展现在外部的只有开关和几个按键。封装可以抽象的理解为就是那个电视机壳子,它将复杂的东西“包”起来,只保留简单的对外接口。
专业一点来说,封装就是将对象的属性和方法尽可能隐藏内部的复杂性,只保留有限的简单的对外接口便于外界的调用。封装的特性使得对象以外的部分不能随意存取对象的内部数据(属性),保证了程序和数据不受外部干扰且不被误用,从而提高系统的可扩展性、可维护性。我们的程序设计要追求“高内聚,低耦合”,高内聚 :就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合 :仅暴露少量的方法给外部使用
那么我们如何去实现封装呢?实现封装,需要使用访问控制符,访问控制符一共有四种,public(公共的),protected(受保护的),default/friendly(默认的/友好的),private(私有的)。
对于类的访问权限只有两种:
1、public 可被同一项目中所有的类访问。 (必须与文件名同名)
2、default/friendly 可被同一个包中的类访问
对于类中成员(成员变量或成员方法)访问权限共有四种:
1、public 可以被项目中所有的类访问。(项目可见性)
2、protected 可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问
3、default/friendly 可以被这个类本身访问;被同一个包中的类访问。(包可见性) •
4、private 只能被这个类本身访问。(类可见性)
封装要点:
类的属性的处理:
1、一般使用private。 (除非本属性确定会让子类继承)
2、提供相应的get/set方法来访问相关属性。这些方法通常是public,从而提供对属性的读取操作。
3、boolean变量的get方法是用:is开头!
4、一些只用于本类的辅助性方法可以用private,
5、希望其他类调用的方法用public
接下来我们用一个程序去具体的理解封装:
package cn.cou.pack;
public class TestEncapsulation { //此类可被同一项目中所有的类访问
public static void main(String[] args) {
Human h = new Human();
//h.age = 13; //在此处age用不了
h.age1 = 13;
h.age2 = 14;
h.age3 = 15;
h.sayAge();
}
}
class Human { //此类为默认权限default,可被同一个包中的类访问
private int age; //只在此类(Human)中可用
int age1; //可被同一包中的类访问
protected int age2; //可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问
public int age3; //可以被项目中所有的类访问
void sayAge() {
System.out.println(age);
}
}
二、继承
java的继承通过extends关键字来实现,实现继承的类被称为子类,被继承的类称为父类,父类和子类的继承关系是从一般到特殊的关系,比如说,水果和苹果的关系,苹果继承了水果,苹果是水果的子类,水果是苹果的父类。另外,extends的英文意思是“扩展”,至于为何国内把他翻译成继承就不知道了,因此,我们可以理解为,子类是父类的扩展,子类会获得父类的全部属性和方法,但是要注意的是子类不能获得父类的构造方法,以及父类中被private修饰的变量或方法。
java中只有单继承,也就是说,一个子类只能继承自一个父类,每个子类只有一个直接父类,不过,一个父类是可以有多个子类的,这一点可以联想到树形图。java中可以通过接口实现多继承。不过多继承是有弊端的,多继承会引起混乱,使得继承链过于复杂,系统难于维护。就像我们现实中,如果你有多个父母亲,那是一个多么混乱的世界。多继承,就是为了实现代码的复用性,却引入了复杂性,使得系统类之间的关系混乱。
如果定义一个类时,没有调用extends,则它的父类默认是:java.lang.Object。
我们沿用并加以扩展上面讲述封装时的程序,进行详细描述:
package cn.cou.pack;
public class TestExtends { //此类可被同一项目中所有的类访问
public static void main(String[] args) {
Human1 h = new Human1();
//h.age = 13; //在此处age用不了
h.age1 = 13;
h.age2 = 14;
h.age3 = 15;
h.sayAge();
Man man = new Man();
//man.age = 1; // 此处age依然不可用,private修饰的age只在Human1类中可用
man.age1 = 2;
man.age2 = 3;
man.age3 = 4;
man.sayAge();
man.work();
}
}
class Human1 { //此类前没有修饰,说明为默认权限default,可被同一个包中的类访问
private int age; //只在此类(Human1)中可用
int age1; //(默认权限default)可被同一包中的类访问
protected int age2; //可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问
public int age3; //可以被项目中所有的类访问
void sayAge() { //此方法前没有修饰,说明为默认权限default,可被同一个包中的类访问
System.out.println(age);
}
}
class Man extends Human1{ //子类Man继承父类Human1
void work() {
System.out.println("工作工作工作!!!");
}
}
接下来详细的说一下,子类与父类在继承后,变量、方法的关系:
1、子类可以继承父类的所有特性,但其可见性,由父类成员变量、方法的修饰符决定。
①、对于被private修饰的类成员变量或方法,其子类是不可见的,也即不可访问;
②、对于定义为默认访问(没有修饰符修饰)的类成员变量或方法,只有与父类同处于一个包中的子类可以访问;
③、对于定义为public或protected 的类成员变量或方法,所有子类都可以访问。
2、子类中可以声明与父类同名的成员变量,这时父类的成员变量就被隐藏起来了,在子类中直接访问到的是子类中定义的成员变量。
3、子类中也可以声明与父类相同的成员方法,包括返回值类型、方法名、形式参数都应保持一致,称为方法的重写(override),重写方法不能使用比被重写方法更严格的访问权限(由于多态)。
4、被隐藏的父类成员变量、方法是可以被引用的,通过super来实现对被隐藏或被覆盖的父类成员的访问。
①、访问父类被隐藏的成员变量和成员方法: super.父类成员变量名
②、调用父类被隐藏的方法:super.父类成员方法名([参数列表])
③、调用父类的构造方法:super([参数列表]),需要注意到是:super( )只能在子类的构造函数中出现,并且永远都是位于子类构造函数中的第一条语句。
下面用程序举例说明,请详细分析,好好理解:
package cn.cou.pack;
public class TestExtends { //此类可被同一项目中所有的类访问
public static void main(String[] args) {
Human h = new Human();
//h.age = 13; //在此处age用不了
h.age1 = 13;
h.age2 = 14;
h.age3 = 15;
h.sayAge();
Man man = new Man();
//man.age = 1; // 此处age依然不可用,private修饰的age只在Human类中可用
man.age1 = 2;
man.age2 = 3;
man.age3 = 4;
man.sayAge();
man.work();
}
}
class Human { //此类前没有修饰,说明为默认权限default,可被同一个包中的类访问
private int age; //只在此类(Human)中可用
int age1; //(默认权限default)可被同一包中的类访问
protected int age2; //可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问
public int age3; //可以被项目中所有的类访问
long number = 8000000000L;
void sayAge() { //此方法前没有修饰,说明为默认权限default,可被同一个包中的类访问
System.out.println("age1 = "+age1);
System.out.println("fnumber = "+number);
}
Human() //父类的构造方法(每一个类都至少有一个构造方法,如果此处我们不写,系统会默认为我们创建一个无参的构造方法,而且不显示)
{
}
}
class Man extends Human{ //子类Man继承父类Human
long number = 40000000000L;//覆盖了父类的number变量
void sayAge() //隐藏了父类的sayAge方法
{
System.out.println("age1 = "+age1);
System.out.println("znumber = "+number);
}
void work() {
System.out.println("工作工作工作!!!");
System.out.println("super.number = "+super.number);//调用父类中被隐藏的成员变量
super.sayAge();//调用父类的sayAge方法
}
Man()//子类的构造方法
{
super();//调用父类的构造方法
}
}
值得注意一点是:Object类是所有java类的根基类,如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类 ,比如上述代码中TestExtends类,未指明其父类,则其父类就为Object类。如果你使用的编译软件是eclipse,可以选中TestExtends类,点Ctrl+T,就可以查看他的继承关系。
三、多态(polymorphism)
多态指的是同一个方法调用,由于对象的不同可能会有不同的行为,比如在我们现实生活中,用同一个方法比如玩,不同的对象,比如男生玩可能就是打游戏,女生玩可能就是逛街买东西。同样都是玩,对象不同,行为可能就会不同。
多态的定义格式:
定义格式:父类类型 变量名 = new 子类类型();
多态的要点:
1、多态是方法的多态,不是属性的多态,多态与属性无关。
2、多态的存在要有3个必要条件:要有继承,要有方法重写,父类引用变量指向子类对象
3、父类引用变量指向子类对象后,用该父类引用调用子类重写的方法,此时就出现了多态。
引用变量的两种类型:
1、编译时类型(一般是一个父类):由声明时的类型决定
2、运行时类型(运行时,具体是哪个子类就是哪个子类):由实际对应的对象类型决定。
对象的转型:
父类引用变量指向子类对象,这个过程称之为向上转型(子转父),属于自动类型转换,向上转型后的父类引用变量只能调用它编译时类型的方法,不能调用它运行时类型的方法。如果想要调用它运行时类型的方法,需要进行类型的强制转换,我们称之为向下转型(父转子),在向下转型过程中,必须将引用变量转成真实的子类类型(运行时类型),否则会出现类型转换异常。
1、向上转型,多态本身就是向上转型过的过程
使用格式:父类类型 变量名 = new 子类类型();
注意: 上转型对象不能操作子类新增的成员变量和方法,可以操作子类继承或重写的成员变量和方法 ,如果子类重写了父类的某个方法,上转型对象调用该方法时,是调用的重写方法。
2、向下转型,一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名 =(子类类型) 父类类型的变量;
拓展:instanceof关键字,它的作用是用来判断某个对象是否属于某种数据类型。返回值类型为布尔类型。
案例:
package cn.cou.pack;
public class TestPolymorphism { //此类可被同一项目中所有的类访问
public static void main(String[] args) {
Human2 h = new Human2();
System.out.println("-----------父类:");
h.Hu();
h.stu();
Man1 man = new Man1();
System.out.println("-----------子类:");
man.Hu();
man.study();
Human2 m = new Man1();//自动向上转型(编译时系统认为 m 是Human2的类型,只有在运行时才知道是Man1的类型)
System.out.println("----------子转父:");
m.Hu(); //调用的是子类重写的方法
m.stu(); //父类方法
//m.study(); //不能使用子类新增的成员变量和方法
if(m instanceof Man1)
System.out.println("m是Man1的类型");
else
System.out.println("m是Human2的类型");
Man1 n = (Man1) m;//强制向下转型
System.out.println("----------父转子:");
n.Hu(); //子类重写的方法
n.stu(); //父类方法
n.study(); //子类方法
System.out.println(n instanceof Man1);//判断n是否是Man1的类型
}
}
class Human2 {
void Hu() {
System.out.println("Hu");
}
void stu() {
System.out.println("学习!");
}
}
class Man1 extends Human2{ //子类Man1继承父类Human2
void Hu() { //重写Hu方法
System.out.println("Ma");
}
void study() {
System.out.println("好好学习天天向上!");
}
}
结果:
-----------父类:
Hu
学习!
-----------子类:
Ma
好好学习天天向上!
----------子转父:
Ma
学习!
m是Man1的类型
----------父转子:
Ma
学习!
好好学习天天向上!
true
3233

被折叠的 条评论
为什么被折叠?



