面向对象
- 面向对象的程序设计思想(Object Oriented Programming),简称OOP.是一种设计者思想.
- 关注的焦点是类,参照现实中的事务,将事务的属性特征,行为抽象出来,用类来表示.
- 代码结构:以类为组织单位,每种事务都有自己的属性和行为,功能,
思想:从宏观上 帮助我们把握,整体分析整个系统,但是,具体到实现时,仍需要面向过程的思路去处理
所以,面向对象离不开面向过程.
类和对象:
类:具有相同特征的事务的抽象描述,是抽象的,概念意义上的定义
对象:实际存在的该类事务的每个个体,是具体的,因此也称为实例.
可以理解为 类----->抽象概念的人 对象----->实实在在的某个人
类的结构
- 变量->事务属性的描述
- 方法->事务的行为
- 构造方法->初始化对象
- 块->一段没有名称的代码块
- 内部类->在类中声明的类
对象:是类的一个实例,是以类为模板在内存中创建的实际存在的实例.
Student s = new Student();
解释:使用Student 类作为类型声明一个变量s,然后调用Student类的构造方法初始化对象,将右边创建的对象的地址赋给左边的变量s,每一个对象都有不同的存储空间.
对象是类的一个实例,必然具备该类事务的属性和行为即方法,使用对象名,属性或者对象名,方法的访问对象成员(包括属性和方法)
小结
类是一类事务的抽象概念,是一个模型,对象是这个模型所创造的,一个个具体存在的,实实在在的实例.所以创建对象的过程也叫做实例化队形,在现实生活中现有对象后有类,而在编程时先设计类后创建对象,
构造方法 :
构造方法与类名相同,且没有返回值,且不需要void修饰
作用:在构造方法中为创建的对象成员变量初始化赋值
特点:每个类都有构造方法,如果没有显示地为类定义构造方法,java会为该类提供一个默认的无参的构造法方法,但是只要在一个类中定义了有参的构造方法后,默认的无参的构造方法就会失效.
一个类可以有多个构造方法
例如
public class Student {
public Student (){
}
public Student(String name)
{
}
}
方法的重载:
方法的重载指的是在一个类中具有相同的名字但是参数不同的多个方法
1 数量可以不同
2类型可以不同
3顺序可以不同
调用时可以根据不同的参数选择相对应的方法,注意:方法的重载与返回值类型没有任何关系
对象与引用
Java中除了基本类型之外的变量都称为引用类型
Java中的对象是通过引用对其操作的
例如: Student s = new Student()
右边的new Student() 是以Student类为模板 在堆空间中创建了一个Student类对象
左边的Student s创建了一个Student类型的引用变量 所谓的Student 类的引用,就是可以用来指向Student对象 的对象引用.
拆分为
Student s;
s = new Student();
第一个是对象的引用变量,第二个是对象本身
解释:
new Student()在堆空间中创建了实体,但是我们看不见摸不着,所以创建一个引用变量来指向它.而例如 Student s1; s1 = s ;这样的发生了复制行为,对象本身没有被复制, 被赋值的只是对象的引用.也就是说s和s1同事指向一个对象,
值传递与引用传递
值传递 形式参数是基本类型 ----形式参数只是用实际的参数值初始化自己的存储单元,是两个不通过的存储单元,所以在方法执行的过程中形式参数的值不改变实际参数的值.
引用传递:形式参数类型是引用数据类型参数;也称为传地址,方法调用时,实际参数是对象,,形式参数接收的是对象的地址,那么在方法的执行过程中,对形式参数的操作也就是对实际参数的操作,所以在方法的执行过程中形式参数的改变会影响实际参数.
无论是值传递还是引用传递,其本质都是传值,所以也都称为,值传递.
this关键字
作用 :
this代表当前对象
在一个类的方法或者构造方法内部,可以使用 this.成员变量名 这样格式来引用成员变量名,常常用来区分同名的成员变量和局部变量.
Static关键字
Static被称为静态,可以修饰类的成员变量成员方法,代码块,内部类,
静态成员不依赖与类的实例,被类的所有实例共享,也就是说static修饰的方法或者变量不需要依赖于对象来进行访问,只要这个类被加载,静态成员就会被加载创建
static成员变量特点:
- 随着类的加载而加载
- 优先于对象存在
- 修饰的成员,被所有的对象共享
- 可以不创建对象,直接使用类名调用 ,也可以通过对象.静态变量的方式访问.
- 静态变量可以再任意方法,代码块,构造器中直接使用.
静态的属性是所有对象共享的,即不管创建了多少个对象,静态属性在内存中只有一个
static成员方法特点
- static修饰的成员方法就是静态方法,
- 静态方法在本类的任意方法,代码块,构造器中都可以直接被调用.
- 静态方法在其他类中可以通过类名,静态方法的方式调用,也可以通过对象,静态方法的方式,调用(但更推荐使用类名,静态方法的方式)
- 在static方法的内部只能访问类的static修饰的属性或者方法,不能访问类非static的成员
- 由于不需要实例就可以访问static方法,因此,static方法内部不能有this,也不能有super
代码块:
在类中声明,没有名称的方法体,代码分为实例块和静态块
实例块:每次创建对象时会自动调用,
静态块 用static修饰,类加载时会自动调用,仅一次.与是否创建对象无关
权限修饰符:
public | protect | default | private | |
同类 | ok | ok | ok | ok |
同包 | ok | ok | ok | |
不同包子类 | ok | ok | ||
不同包的其他类 | ok |
面向对象的特征:
封装,继承,多态
封装:
将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对该类隐藏信息的操作和访问,
具体表现,例如将成员变量设置为私有,将成员方法设置为共有,通过共有的方法,set和get方法来获取和修改成员变量的值, 就不能够通过 对象.成员变量 的方式来访问
补充:
成员变量和局部变量
在类的位置不同
成员变量,在类中定义
局部变量,在方法中定义或者方法的参数
权限修饰符不同
成员变量:可以使用权限修饰符
局部变量:不可以使用权限修饰符
初始化不同
成员变量:创建对象后,由构造方法初始化,
局部变量:没有默认的初始化,必须定义,赋值.
生命周期不同
成员变量:随着对象的创建而存在,随着对象的销毁而销毁,
局部变量:随着方法的调用而存在,随着方法调用完毕而消失.
在内存中的位置不同
成员变量,与对象一起存在内存中,局部变量,与方法一样存在栈中.
继承
多个类中存在相同的属性和行为时,将这些内用抽取到单独的一个类中,那么,多个类,中无需再定义这些属性和行为,只需要和抽取出来的类后塍继承关系.
继承的好处
减少代码的冗余,提高了代码的复用性
有利于功能的扩展
让类与类之间出现了is-a的关系,为多态的使用提供了前提.
何时使用继承
符合is-a关系的设计,可以使用继承
例如: 猫是动物 狗是动物 那么就可以单独抽取一个动物类,让猫类和狗类去继承动物类
继承的语法
通过extends 关键字可以声明一个类去继承另外一个类,例如
修饰符 class 类A extends 类B{
}
类A称为子类,类B成为父类
继承的细节
- 子类会继承父类所有的实例变量和实例方法
- 子类不能访问父类私有的private的成员变量和方法
- Java中继承的关键字是extends 表示子类对父类的扩展
- Java支持多层继承(继承体系)
- 一个父类可以同时拥有多个子类
- Java只支持单继承,不能支持多重继承也就是说一个子类不能同时继承多个父类
类java.long.Object是所有类的根类,即所有其他类的父类.每个类都使用Object类作为超类,当一个类没有显示继承其他类时,默认继承Object.
关于内存分配:
- 堆:存放所有对象实例及数组
- 栈:每个线程都有自己的栈,用于存储局部变量和部分方法调用的信息
- 方法区 :存储类信息,常量,静态变量.
在子类继承父类时,子类会从父类继承字段和方法。但这种继承并不需要在方法区中为子类重新创建一个独立的内存空间来存放这些继承的成员。相反,子类会有一个指向父类的方法和字段的引用。
方法的重写:
当父类的方法功能不能够实现子类需求时,可以对方法进行重写,
子类可以对父类中继承来的方法进行改造,我们在程序执行时,子类的方法将覆盖父类的方法,我们称为方法的重写也成为方法的覆盖
注意,构造方法,静态方法不能重写,成员变量不存在重写.
重写规则
- 子类重写的方法必须和父类的方法名称,参数列表相同
- 子类重写的方法的返回值类型与父类保存一致
- 子类重写的方法的使用权限不能小于父类被重写方法的访问权限
- 子类方法抛出的异常不能大于父类被重写方法的异常
解释第三条
如果父类是public反法,子类将其降低为private那么在实现多态时,父类的引用指向子类的对象,父类调用这个子类的方法,但显然子类时private无法调用,所以无法实现多态
官方解释:子类不能继承父类的私有属性,但是,如果子类中共有的方法,影响到了父类私有的属性,那么私有属性是能够被子类使用的,
@Override使用说明:
@Override是java中定义的注解标签写在方法上面,表示此方法是从父类重写而来,用来检测是否满足重写方法的要求,帮助我们检查格式.
super关键字
在Java类中使用super来调用父类中的指定操作:
super可用于访问父类中定义的属性,
super可用于调用父类中定义的成员方法
super可用于在子类构造器中调用父类构造器.
注意:
当子父类出现同名成员时,可以使用super表名调用的是父类的成员,super的追溯不限于直接父类还可以是父类的父类.super和this的用法很像,this代表本类的引用,super代表父类的内存空间的标识.
super在创建子类对象时,不会创建父类对象,例如当在子类的构造方法中调用super(...),实际上是调用了父类的构造方法,而不是创建一个新的父类对象.
补充---->对象创建过程:
当创建一个类的对象时,不会单独创建一个父类的对象,相反,父类中的成员变量和方法会被直接包含在子类对象中,就好像是这些方法本来就是子类中的一部分一样
继承中的构造方法:
- 子类继承父类时,不会继承父类的构造方法,只能通过super(.....)的方式调用父类指定的构造方法,
- 规定super(形参列表),必须在构造器的首行
- 如果子类构造器没有显示调用super形参列表则子类构造器会默认调用super()即调用父类构造器中的无参的构造器
- 先调用父类的构造器是为了保证父类成员先初始化.
注意
如果子类构造器中既没有显示地的调用父类构造器,而且父类中又没有无参的构造器,则编译出错 .
抽象类
抽象方法
抽象方法是一种特殊的方法;他只有声明而没有具体的实现,抽象方法必须使用abstract关键字进行修饰.
抽象类
- 如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类.
- 抽象类除了不能实例化对象之外,类的其他功能都存在,成员变量,成员方法,和构造方法.
- 使用abstract修饰的类就是抽象类,如果某个类中包含右抽象方法,那么该类就必须定义为抽象类,
- 当子类继承抽象类时.必须要实现父类中的所有的抽象方法.且该方法的参数,返回值,参数和抽象方法一样,否则,子类也必须声明为抽象类.
具体格式
public abstract class 类名{ //仅含有成员变量的抽象类
成员列表;
}
public abstract class 类名{ //含有抽象方法的抽象类
public abstract void draw();
}
多态
父类的引用指向子类的对象
例如
Person p = new Student();
同一事物在不同时刻表现不同的状态, 例如上述代码,首先声明一个Person(父类)类型的引用p 然后创建类Person的子类Student类的对象,,,父类的p的引用指向子类的对象new Student();
二者存在直接或者间接的继承成关系时,父类的引用指向子类的对象,即形成多态.
编译时期是父类,运行期间是子类
例如上述代码块,编译期间P是Person类,所以只能调用父类Person类中的方法,如果子类冲写了父类的方法,则运行时调用子类重写的方法.
多态的好处:提高代码的扩展性
例如,方法的形式参数是父类类型,而传递的实际参数可以是任意的子类对象.
多态环境下对成员方法的调用------->简单来说编译看左边,运行看右边
解释,编译时期只能调用的是父类中的方法也就是父类Person的方法,而运行期间如果子类中重写了此方法,则调用子类中重写后的方法,.也就是后面子类Student的方法.
多态环境下对静态方法的调用------->编译和运行都看右边
例如
class Person{
Static void work()
{
System.out.println("赚钱");
}
class Student entends Person{
Static void work(){
System.out.println("学习");
}
}
Person p = new Student ()
p.work();
这里的P调用的是父类中的方法
解释
Person
类被加载并初始化,work()
方法变为可用。Student
类被加载并初始化,work()
方法隐藏了Person
类的work()
方法。- 创建一个
Student
对象,并将其赋值给Person
类型的引用p
。 - 调用
p.work()
时,由于work()
是静态方法,根据引用类型Person
调用Person
类的work()
方法,而不是Student
类的work()
方法。
总结,
实例方法是基于对象绑定的,方法调用时看的是对象.
静态方法时基于类绑定的,方法调用时看的是类.
多态环境下对成员变量的调用
class Animal {
int num = 3;
void displayNum() {
System.out.println(num);
}
}
class Cat extends Animal {
int num = 4;
@Override
void displayNum() {
System.out.println(num);
}
}
Animal x = new Cat()
System.out.println(x.num); // 输出 3
编译和运行都看左边,子类重写只能重写方法,不存在重写成员变量,所以编译和运行都是左边.
x.displayNum(); // 输出 4
final关键字
修饰类,方法,参数,和属性
类:不能定义为抽象类,或是接口.不可以被继承
方法:子类里不能重写
参数:数值在方法中不可以被修改
属性:定义时就必须赋值或者在构造方法中赋值.并且后期不能修改
接口
使用interface关键字来声明一个接口例如
public interface Student extends Person,Work {
}
使用implements关键字来实现接口,在类中,implements关键字放在class声明后面
public class Student implements 接口1,接口2{
}
也可以
public interface Student extends Person,Work implements 接口1,接口2 {
}
特点
- 隐式抽象,主要定义功能
- 一个接口可以继承多个其他接口
- 接口不被实例化对象
- 当类实现接口时,类要实现接口中的所有的抽象方法,否则,该类必须被声明为抽象类.
- 接口与实现类中存在多态性