第三章 面向对象
3.1面向对象的概念
3.3.1理解面向对象
1.面向对象是相对面向过程而言
2.面向对象和面向过程的区别
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
3.3.2面向对象的特点
1、是一种符合人们思考习惯的思想
2、可以将复杂的事情简单化
3、将程序员从执行者转换成了指挥者
4、完成需求时:
l先要去找具体所需的功能的对象来用
l如果该对象不存在,那么创建一个具有所需功能的对象
l这样简化开发并提高了复用性
3.3.3面向对象开发,设计,特征
1、开发的过程:其实就是不断创建对象,使用对象,指挥对象做事情
2、设计的过程:其实就是在管理和维护对象之间的关系
3、面向对象的特征:
封装(encapsulation):封装是面向对象的核心思想,将对象的属性和行为封装起来,而它的载体是类,类通常对客户隐藏细节。
继承(inheritance):使用已存在的类的定义作为建立新技术的基础,新类的定义可以增加新的数据或功能,也可以使用父类的功能。
多态(polymorphism):动态绑定机制,用来决定会使用被重写的方法名的那个方法的行为。
3.2类与对象的关系
3.2.1类与对象的关系
1、对象——类的实例
它是实际存在的该类事物的个体。面向对象程序设计思想是以对象来思考问题,首先将现实世界的尸体抽离为对象,然后考虑对象具备的行为和属性。
2、类:类是同一类事物的统称,是构造对象时依赖的规范,
3.2.2类的定义
1、类定义的内容:
⑴、成员变量:也叫成员域,是对象的属性
①、类变量:被该类全部共享的变量,也称静态成员域,常用于保存所有对象共有的常数值。
②、实例变量:也称非静态成员域
⑵、方法:也叫成员函数,是对象的行为。
①、类方法:即使该类对象没有对象存在时,也可以执行类方法。它也用static进行声明,因此也被称为静态方法
②、实例方法
3.2.3成员变量和局部变量的区别?
1.作用范围:成员变量可以被public,protect,private,static等修饰符修饰,局部变量不能被控制修饰符及static修饰;两者都可以定义成final型
2.是否有默认值:成员变量有,局部变量木有
3.生命周期:成员变量随对象的建立而存在,随其消失而消失;局部变量随所属区域的执行而产生,随其释放而释放
4.存储位置:成员变量存储在堆,局部变量存储在栈
3.2.4匿名对象
1、其实就是定义对象的简写格式:new 对象名();
2、使用场景:①、当对象方法仅进行一次调用时,就可以简化成匿名对象
②、可以作为实际参数进行传递
3.2.5参数传递——值调用
1、值调用:将实际参数的内容拷贝到被调用方法。
2、基本数据类型:创建时存储于栈中。在调用时,会将将其copy拷贝到被调用方法的栈中。然后方法method根据传过来的参数进行方法的执行。
3、引用数据类型:引用类型的引用存储于栈中,而对象则是存储与堆中。在调用时,会将对象的地址拷贝到被调用方法的栈中。然后方法method根据传过来的参数进行方法的执行。
3.3 封装
1、定义:隐藏对象的属性和实现细节,对外提供公共的访问方式
class Person{
//隐藏age这个属性,一旦有属性,几乎都封装,
private int age;
//提供对外访问方式,是为了可控
public void setAge(int a) {
age = a;
}
public int getAge(){
return age;
}
2、好处
n将变化隔离。
n便于使用
n提高重用性
n提高安全性
3 原则
l将不需要对外提供的内容都隐藏起来。
l把属性都隐藏,提供对外访问方式。
4、private关键字
n作用:利用private关键字,可以修饰成员,私有的内容只在本类中有效。
n封装与私有的关系:私有是封装的子集,私有仅仅是封装的一种体现而已
n在java中最小的封装体是函数。
3.4 构造函数
1、特点:⑴函数名与类名相同
⑵不定义返回值类型,没有具体的返回值
2、作用:给对象进行初始化,创建对象都必须要通过构造函数初始化
3、默认构造函数:一个类中如果没有定义过构造函数,那么该类会有一个默认的空参构造函数,如果定义了,类中就没有默认的啦。
4、与一般函数的区别:⑴构造函数:对象创建时,就会调用与之对应的构造函数,对对象进行初始化,一般函数:对象创建后,需要函数功能时才调用。
⑵构造函数在对象创建时会调用,而且只调用一次;一般函数在对象创建后,可调用多次。
5、重载:
什么时候使用构造函数?在描述事物的时候,该事物一创建,就具备的一些内容,这些内容定义在构造函数中。
如果构造函数有多个,用于对不同对象进行针对性的初始化,多个函数在类中是以重载的形式来体现的。
6、注意:⑴、方法的名称、形式参数的类型及其顺序形成了方法的签名,签名是唯一
⑵、在构造函数前,不能加返回类型。
⑶、一般函数不可以调用构造函数,原因是构造函数是对对象初始化函数,不能被调用,非得调用就得用:new 构造函数();但这是废话、
⑷、构造函数中也有return语句。
3.5 this关键字
1、使用场景
⑴、当定义类中功能时,该类函数内部要用到调用该函数的对象时,这是用this来表示这个对象,即本类功能内部用到本类对象的时候,用this。
①、区分同名的局部变量与成员变量,this代表本类的对象,到底代表哪一个?this代表它所在函数所属对象的引用。简单说:哪个对象在调用this所在的函数,this就代表哪个对象
②、在本类方法中使用对象,用this。
③、凡是被对象调用的方法,在内存中都有this所属
⑵用于构造函数间的相互调用
2、注意:this只能放在构造函数中第一个,因为初始化动作要先执行
3、代码示例
class Person{ private int age; private String name; /*public Person(int age) { this.age = age; }*/ Person(String name){ this.name = name;//将局部的赋给对象的变量 } Person(String name, int age){ //Person(name);这是一般函数间的调用 this(name);//这是构造函数间的互相调用,在这里,this(name)相当于p(name),也就是new Person(name); this.age = age; } public void shout(){ System.out.println("My age is "+age+"\nMy name is "+name); } /* * 需求:给人定义一个用于比较年龄是否相同的功能 * public boolean compare(Person p){ return this.age == p.age; }*/ } public class AboutThisKey { public static void main(String[] args) { /*Person p1 = new Person(20); Person p2 = new Person(25); boolean b = p1.compare(p2); System.out.println(b); */ Person p = new Person("lisi",30); // Person p1 = new Person("zhangsan"); p.shout(); // p1.shout(); //为什么p1不打印My age is 0 My name is lisi,而p不打印My age is 0 My name is zhangsan //在一个类里面,成员之间互相调用时都是对象完成的,所以shout放完的是某一个对象中的name和age,即name和age之前省略了this } }
3.6 static关键字
1、共享数据:static用于修饰成员(成员函数,成员变量),这些成员都是被对象共享的成员。
2、特点
①、随类的加载而加载,消失而消失。
②、优先于对象而存在
③、被所有对象所共享
④、可以直接被类名所调用
代码示例
class Chinese { static String country = "中国";//共享数据 String name; int age; void singOurCountry(){ System.out.println("啊,亲爱的"+country); } } public class AboutStaticKey { public static void main(String[] args) { System.out.println(Chinese.country); //当成员被静态修饰后,除了可以被对象调用之外,还可以被类名调用 Chinese ch = new Chinese(); System.out.println("Chinese country is " + ch.country); ch.singOurCountry(); } }
3、实例变量与类变量的区别
①、存储位置:前者随对象的建立而存在于堆内存中;后者随着类的加载而存在于方法区中
②、生命周期;前者随着对象的消失而消失;后者随着类的的消失而消失
③、调用方式:前者可以被对象及类名调用,但建议用类名调用;后者只能被对象调用
4、静态的使用注意事项:
①、静态的方法只能访问静态成员
②、静态方法中不可以使用this或super关键字
③、静态省略的是类名,成员变量省略的是this
④、主函数是静态的
public static void main(String[] args)
1)、public:代表着该函数的权限最大
2)、static:代表主函数岁类的加载而加载就已经存在
3)、void:主函数没有返回值
4)、main:不是关键字,是一个特殊的单词,可以被jvm识别。
5)、String[] args:函数的参数,参数类型是一个数组,该数组中的元素师字符串,字符串类型的数组。
5 、静态的利弊
①、利:对对象的共享数据进行单独空间的存储,节省空间,可以被类名直接调用。
②、弊:生命周期过长,而且访问有局限性
6、什么时候使用静态?
①、静态变量:如果对象中出现共享数据时,该数据被静态修饰,对象中的特有数据定义在堆内存中
②、静态函数:函数是否用静态修饰,就看该函数功能是否需要访问对象中的特有数据,需要,该功能为非静态;不需要,就定义成静态
7、静态代码块
①、格式:static{
code;
}
②、特点:随类的加载而执行,且只执行一次,并优先于主函数而执行
③、作用:给类进行初始化
8、面试题
class StaticCode {
StaticCode(){
//因为没有创建过与之相关的对象,从而没有被执行过,所以不打印b
System.out.println("b");
}
static{//静态代码块给类初始化
System.out.println("a");
}
{//构造代码块给对象初始化,其优先级比构造函数高,因为构造函数有针对性,而构造代码块可以初始化所有对象
System.out.println("c");
}
StaticCode(int x){//构造函数给对应的对象初始化
System.out.println("d");
}
public static void show(){
System.out.println("show run");
}
}
class StaticCodeDemo {
public static void main(String[] args) {
new StaticCode(4);
}
}
问打印结果是?为什么?
结果:a c d,
3.7 单例设计模式
1、设计模式:解决一类问题最行之有效的方法
2、单例设计模式:保证内存中只有一个对象
3、原因:以配置文件为例,
4、如何保证对象的唯一性?
1)、不允许其他程序用new建立该类对象
2)、为了让其他程序可以访问到该类对象,在本类中,定义一个对象
3)、为了让其他程序对自定义对象可以访问,可以对外提供一些访问方式
5、以上3部怎么用代码体现?
1)、将构造函数私有化
2)、在类中创建一个本类对象
3)、提供一个方法可以获得该对象
6、模式:
①饿汉式:定义单例时,建议使用饿汉式
class Singleton{
private int num;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
private Singleton(){}
private static Singleton s = new Singleton();
public static Singleton getInstance(){
return s;
}
}
②懒汉式:对象的延时加载,懒汉式在面试的时候考的最多
class Singleton{
private int num;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
private Singleton(){}
private static Singleton s = null;
public static Singleton getInstance(){
if(s==null){
synchronized(Singleton.class){
if(s==null)
s = new Singleton();
}
}
return s;
}
}
public class SingletonPattern {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
s1.setNum(30);
System.out.println(s2.getNum());
}
}
3.8 继承
3.8.1继承的概述
1、继承:Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。
2、继承的优点
①、提高了代码的复用性
②、让类与类之间产生了关系,有了这关系,才有了多态的特性
注意:千万别因为要获取其他类 的功能,简化代码而继承,必须是类与类之间有所属关系才可以继承。
3、父类,也称为基类,或超类
4、 聚集关系:关联的一种形式,代表两个类之间的整体 / 局部关系。聚集暗示着整体在概念上处于比局部更高的一个级别,而关联暗示两个类在概念上位于相同的级别。
有两种特殊聚集:共享聚集和组合聚集。
l共享聚集:它的“部分”对象可以是多个任意“整体”对象的一部分
l组合聚集:整体拥有各部分,部分与整体共存。
3.8.2继承的特点
1、java语言:只支持单继承,不支持多继承,因为多继承容易带来安全隐患:当多个父类中定义相同功能,而功能的内容不同,子类不确定要运行哪一个但是java保留了这种机制,并以另一种体现形式来完成表示,多实现
2、java支持多层继承,也就是一个继承体系。如何使用一个继承体系中的功能?想要使用体系,先查阅体系父类的描述,因为父类定义了该体系的共×××,通过了解共×××,就可以知道该体系的基本功能。在具体调用时,要创建最子类对象,其原因是父类有可能创建不了对象,另外创建子类可以使用更多的功能。
3、子父类出现,类成员的特点:
⑴、变量:如果子父类中出现非私有的同名成员变量时,子类要访问本类中的变量时用this,子类要访问父类中的变量时用super。他们俩的用法几乎一致,只是俩代表的引用不同
⑵、函数:当子类出现和父类一模一样的函数时,子类对象调用该函数会运行子类函数的内容,如同父类的函数被覆盖了一样,也叫重写或覆盖。
当子类继承了父类,沿袭了父类的功能,到子类中,但是子类虽具备该功能,但是功能的内容和父类不一致,这时,只需覆盖父类功能,保留父类的功能定义,并重写功能内容。
通过函数的复写可以提高扩展性
覆盖注意事项:
1)、子类的权限必须大于等于父类的权限,才可以覆盖。
2)、静态只能覆盖静态
3)、重载只看同名函数的参数列表,而重写的子父类方法必须一模一样
⑶、构造函数:
子父类的构造函数是不可能一样的,因为构造函数的函数名与类名一致。在对子类对象进行初始化时,父类的构造函数也会运行。其原因是在子类构造函数默认的第一行有一条隐式的语句super(注意当第一行是this(),就没有super()),super会访问父类中空参数的构造函数。
为什么子类一定要访问父类的构造函数?因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的的,所以子类在对象初始化时,要先访问父类的构造函数。如果要访问父类中指定构造函数,可以通过手动定义super语句来。
3.8.3 super关键字
1、应用
⑴、在子类的构造方法内部引用父类的构造方法,如果要引用super的话,必须把super放在函数的首位.
class Base { Base() { System.out.println("Base"); } } public class Checket extends Base { Checket() { super();//调用父类的构造方法,一定要放在方法的首个语句 System.out.println("Checket"); } public static void main(String argv[]) { Checket c = new Checket(); } }
⑵、在子类中调用父类中的成员方法或成员变量
class Country {
String name;
void value() {
name = "China";
}
}
class City extends Country {
String name;
void value() {
name = "Hufei";
super.value();//不调用此方法时,super.name返回的是父类的成员变量的值null
System.out.println(name);
System.out.println(super.name);
}
public static void main(String[] args) {
City c=new City();
c.value();
}
}
⑶、用super直接传递参数
class Fu{ int num; Fu(int num){ System.out.println("fu run"+" "+num); } void show(){ System.out.println("fu show"); } } class Zi extends Fu{ Zi(){ //super(); super(4);// 传递参数 System.out.println("zi run"); } void show(){ System.out.println("zi show"); } }
2、注意:
⑴、super语句必须放在子类构造函数的第一行
⑵、super和this都只能定义在第一行,所以只能定义一个。
⑶、通过super初始化父类内容时,子类的成员变量并未显示初始化,等super()父类完毕后,才进行成员变量显示初始化
3.8.4实例化过程
1、子类的实例化过程:
子类的所有的构造函数,默认都会访问父类中的空参数的构造函数。因为子类每一个构造函数的第一行都有一句隐式的super();当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问的父类中的构造函数。当然,子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,子类中至少会有一个构造函数会访问父类中的构造函数
2、对象实例化过程——以Person p = new Person();为例
lJvm会读取指定路径下的Person.class文件,并加载进内存,并会先加载Person的父类
l在堆内存中开辟空间,分配地址。
l在对象空间中,对对象中的属性进行默认初始化
l调用对应的构造函数进行初始化
l在构造函数中,第一行会先到调用父类中构造函数进行初始化
l父类初始化完毕后,再对子类的属性进行显示初始化
l在进行子类构造函数的特定初始化
l完毕后,将地址值赋给引用变量
3.8.6 final关键字
1、final修饰的类不可以继承
2、final修饰的方法不可以覆盖
3、final修饰的变量是一个常量,只能赋值一次,且只固定显示化赋值
4、注意:类变量只有在final的修饰下,值才会固定,否则可以修改,static只能说明该值被共享,但不规定是固定的。
转载于:https://blog.51cto.com/19901111/1246157