一 封装
封装从字面上来看就是包装的意思,Java中指把对象的属性及实现细节隐藏,仅对外提供公共的访问方式。这样用户就不需要知道对象内部的细节,但可以对外访问的方式来访问对象。
原则: 将不需要对外提供的内容隐藏起来。把属性都隐藏,提供对外的公共方法。
好处:
a:类内部的结构可以自由修改,将变化隔离、便于使用、提高重用性、提高安全性。
b:良好的封装能够减少耦合。
(1)体现形式
封装的最常用的体现就是,方法或属性用private修饰符修饰。把属性和方法私有化,不让外部类访问。
例如:
class Preson
{
//私有化属性;
private String name;
private String gender;
private int age;//把age 改为String类型。
public void setName(String name){
this.name=name;
}
public void setName(String name){
this.name=name;
}
public String setGendet(String gender){
this.gender.gender;
}
public void setAge(int age){
//如果年龄大于14岁则提示错误。
if(age>140)
System.out.println("年龄错误,请重新输入");
this.age=String.valueOf(age);//转换为字符串类型。
}
public String getName(){
return name;
}
public String getGender(){
//如果数据库中的名字是用1、0存储的。
if("0".equals(gender)){
Name="女"
}
if("1".equals(gender)){
name="男";
}
else{
name="不男不女";
}
return name;
}
public int getAge(){
return age;
}
}
注意:
方法是Java的最小封装体 私有化的变量无法在外部引用封装不是私有,私有仅仅是封装的一个表现形式。
之所以对外提供set get方式是因为可以在访问方式中加入逻辑判断语句,对访问的数据进行操作,例如可以设置人的名字不能超过120岁,提高健壮性。
二 继承 extends
1 概念
继承是面向对象设计的三大特点,它可以不定义变量和方法,就可以直接使用现有类的变量和方法,继承得到的类称为子类。被继承的类称为父类或超类,Java中所有的类都是直接或间接的继承Object类。
格式:[ 访问修饰符 ] class 子类名 extends 父类名
好处:
(1)代码共享,提高代码的复用性。
(2)让类与类之间产生关系,有了这个关系才有的多态的特性。
缺陷:
(1)父类变,子类就要变。
(2)继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的
(3)继承是一种强耦合关系。
2.特点
java语言中只支持单继承,不支持多继承,但是支持多层继承。
多继承会带来安全隐患。当父类中定义了相同的功能,子类都继承过来,但是运行时不知道运行哪个父类的中的功能,但是Java保留了这种机制,并用另一种体现形式“多实现”来表示。
3.继承应用
如何使用一个继承体系中的功能呢?
想要使用体系。先查阅父类的描述,因为父类中定义的是改体系的共性功能。通过了解共性功能,就可以知道该体系的基本功能。那么这个体系基本可以使用。
在具体调用时,要创建子类的对象,为什么呢?
一是因为父类可能不能创建对象。
二是创建子类对象可以使用更多的功能,包括基本的也包括特有的。
简单说 就是查阅父类的功能,创建子类的对象来使用。
4.方法重载和方法重写
方法重载:方法名相同,参数个数、类型、顺序不相同。
方法重写:子类继承父类后,子类可以重写父类的方法,则被继承父类的方法被覆盖。
5.向上转型和向下转型
向上转型:子类对象指向父类引用,类型提升,动物x=new猫;
向下转型:父类的引用指向自己子类类型,强制转换;动物x=new 猫 ,猫y=(猫)x
但是不能将父类的对象转换成子类类型,动物x=new 动物 猫 y=(猫)x
多态自始至终都是子类对象在做改变。
class Animal
{
public void method(){
System.out.println("我是动物");
}
public static void method(Cat c){
c.method();
}
public static void main(String[] args){
//向下转型;
Animal a=new Animal();
method((Cat)a);
}
}
public class Cat extends Animal
{
publicvoid method(){
System.out.println("我是猫");
}
publicstatic void main(String[] args){
Cat c=new Cat();
//子类继承父类的method方法。
c.method(c);
//向上转型;
Animal a=new Cat();
//a.method();
}
}
注意:向下转型容易出错,所以一般不用。
6. 注意事项
(1)子类拥有父类非private的属性和方法。
(2)对于构造函数而言,它只能够被调用,而不能被继承。
(3)千万不要为了获取其他类的功能,而简化代码来继承
(4)必须是类与类之间有所属关系才叫继承,所属关系isa;即如果有两个对象A和B,如果B是A那么就可以表示为B is A.
8 聚集关系 has a
事物中不光有继承关系,还会有聚集关系,聚集关系又分为聚合和组合。
聚合:一个公司里有职员,一个球队中有一个球员。松耦合,没有谁离不开谁
组合:手是人的一部门。 紧密关系要比聚合更加紧密,不可缺少。
9 this和super
概念:
super代表该类的父类,this代表调用它的对象本身。
(1)super和this.
Super:
a:子类的普通方法可以调用父类的普通方法。
b:子类的构造方法可以调用父类的普通方法。
This:
a:全局变量和局部变量重名时,必须用。
b:构造方法可以调用普通方法。
c:普通方法可以调用普通方法。
class Person
{
String name;
String age;
Person(){
System.out.println("父类构造函数");
}
public void method(){
System.out.println("父类方法");
}
}
public class Student extends Person
{
String name;
int age;
Student(){
System.out.println("子类构造方法");
//this:构造方法调用普通方法。
this.method1();
//super:可以调用父类的普通方法。
super.method();
}
public void setName(String name){
//当局部变量和全局变量重名时,可以用this区分。
//this.name代表的是全局变量。
this.name=name;
}
public void method1(){
System.out.println("子类普通方法1");
//this:普通方法调用普通方法;
this.method2();
//super:子类调用父类普通方法。
//super.method();
}
public void method2(){
System.out.println("子类普通方法2");
}
public static void main(String[] args){
Student s=new Student();
//s.method();
}
}
this为什么可以 解决这些问题?
this代表的是所在函数所属对象的引用。简单说,哪个对象调用this所在的方法,this则代表哪个对象。
(2)super( )和this()
super():
子类构造方法可以调用父类构造方法。
This( );
子类构造方法可以调用子类其他的构造方法。
class Person
{
String name;
String age;
Person(){
System.out.println("父类构造函数");
}
Person(String name){
System.out.println("父类构造函数2"+name);
}
public void method(){
System.out.println("父类方法");
}
}
public class Student extends Person
{
String name;
int age;
Student(){
//默认情况下,子类会自动调用父类的无参数构造函数。如果父类的无参构造函数被覆盖,子类则应该指定。
//super("sss");
this("哈哈");
System.out.println("子类构造方法");
}
Student(String name){
System.out.println("子类构造方法2"+name);
}
public void method1(){
System.out.println("子类普通方法1");
}
public void method2(){
System.out.println("子类普通方法2");
}
public static void main(String[] args){
Student s=new Student();
//s.method();
}
}
注意事项:
(1)调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
(2)super()和this()类似,区别是,super从子类中调用父类的构造方法,this()在同一类内调用其它方法。
(3)super()和this()均需放在构造方法内第一行。
(4)尽管可以用this调用一个构造器,但却不能调用两个。
(5)this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
(6)this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
(7)从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
10 父与子类的关系
(1)变量
a:如果子父类中出现了非私有的同名成员变量时,子类要访问本类中的成员变量要用this
b:子类要访问父类中的成员变量时,用super。
c:super的使用几乎和this的使用一致。this代表本类对象的引用,super代表父类对象的引用。
(2)函数
a:当子类中的函数和父类中的函数一样时,在子类调用该函数时,会运行子类的函数的函数。
b:如同父类的函数被覆盖一样,这种情况叫是函数的另一个特性:重写(覆盖)(另一个特性是重载)。
c:当子类继承父类后沿袭了父类的功能到子类中,但是虽具备该功能,但是功能的内容和父类的内容不一致,这时,没有必要重新定义一个函数,而是使用覆盖特性,保留父类的功能定义,并重写父类功能。
覆盖注意事项:
a:子类覆盖父类,必须保证资料权限大于父类权限,才可以覆盖,否则编译失败。
b:静态只能覆盖静态。
重载:只看同函数的参数列表。
重写:子父类的方法一模一样。
(3)构造函数
在子类对象进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认的第一行都有一个隐式的语句super();它会访问父类中的空参数构造函数,而且子类中的所有构造函数默认的第一行都市super();
为什么子类一定要调用父类的构造函数呢?
因为父类中的数据子类可以直接获取,所以子类在对象建立时,需要先查看父类是如何进行初始化的。所以子类在初始化时要先执行父类的构造函数。如果要访问父类中的指定构造函数的话,可以定义super()语句来指定。
注意:super语句一定要定义在子类构造函数的第一行。
子类的实例化过程:
子类所有的构造函数都会访问父类的空参数构造函数,因为子类每一个构造函数内都有一句隐式的super(),当父类中没有空参数构造函数时,子类必须手动调用super或者this语句来指定要访问的父类的构造函数。有时子类中 的构造函数第一行通过this语句指定的是本类中的构造函数,子类中至少会有一个构造函数能访问父类的构造函数。
三 多态
面向对象的三大特性,封装继承多态,前两种都是为多态做了铺垫。
1 多态的理解
可以理解为事物的存在多种形态。
人(男人、女人) 动物(猫、狗)
猫x=new 猫(),
动物 x=new 猫();
多态的体现:
父类的引用指向了自己子类的对象。
父类的引用也可以接受自己的子类对象。
多态的前提:
实现多态三个必要条件:继承(要不实现),重写、向上转型。
原则:
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
多态的好处和弊处:
好处:多态的出现大大提高了功能的扩展性。
弊端:只能使用父类的引用访问父类的成员。
2 多态中成员的特点
在多态中成员函数(非静态)的特点:
在编译时期:参阅引用型变量所属的类是否有调用的方法,如果有,编译通过,如果没有,编译失败。在运行时期,参阅对象所属的类是否有调用方法。
简单总结:成员函数在多态调用时编译看左边,运行看右边。
涉及面试的环节:
在多态中成员变量和静态函数的特点:
无论编译和运行,都参考左边(引用变量所属的类)
3 多态的应用
(1)基于继承实现:
基于继承主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
示例:
class Fq
{
public void speak(){
System.out.println("我是父亲");
}
}
class Ez1 extends Fq
{
public void speak(){
System.out.println("我是大儿子");
}
}
class Ez2 extends Fq
{
public void speak(){
System.out.println("我是二儿子");
}
}
public class Test1
{
public static void main(String[] args){
Fq f1=new Ez1();
Fq f2=new Ez2();
//调用父亲的说话方法,出现不同的形态。
f1.speak();
f2.speak();
}
}
(2)基于接口实现的多态
继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。类继承都是单继承,而接口可以多实现。
示例:
// 接口PCI
interface PCI
{
public void open();
public void close();
}
//网卡实现接口
class NetCard implements PCI
{
public void open()
{
System.out.println("网卡运行...开始上网");
}
public void close()
{
System.out.println("网卡关闭");
}
}
//声卡实现接口
class SoundCard implements PCI
{
public void open()
{
System.out.println("声卡运行..");
}
public void close()
{
System.out.println("声卡关闭");
}
}
class Computer
{
//电脑运行
public void run()
{
System.out.println("运行电脑");
}
public void close(){
System.out.println("关闭电脑");
}
//使用扩展功能
public void usePci(PCI p)
{
if(!(p==null))
{
p.open();
}
}
public void closePci(PCI p)
{
if(!(p==null))
{
p.close();
}
}
}
public class Test1
{
public static void main(String[] args)
{
Computer c =new Computer();
//电脑运行
c.run();
//电脑上网 PCI p = new NetCard()接口指向子类对象
c.usePci(new NetCard());
//电脑听歌
c.usePci(new SoundCard());
//关闭网卡
c.closePci(new NetCard());
//关闭声卡
c.closePci(new SoundCard());
//关闭电脑
c.close();
}
}
/**
运行结果:
运行电脑
网卡运行...开始上网
声卡运行...开始听歌
网卡关闭
声卡关闭
关闭电脑
*/