黑马程序员——面向对象三大特征(封装、继承、多态)

来源:互联网 发布:金华亿途网络 编辑:程序博客网 时间:2024/05/21 07:02

------------ android培训、java培训、期待与您交流! -------------

面向对象的特征:封装、继承、多态

面向对象特点:

1、   面向对象是将功能封装,强调了具备功能的对象,

2、   面向对象是基于面向过程的。将复杂事情变简单、将执行者转变为指挥者、人开门(开门的方法的属于门的) ps:去买电脑,自己不懂就要咨询,上网查资料,这个过程很麻烦,但是可以找个懂电脑行情的人,就可以调用他的方法,变的简单

            最牛的例子是到哪到说到哪,灵活利用现实的环境,会拍马屁,推销自己。

名词提炼法:

             以后的开发就是找对象,没对象创建对象。找对象,建立对象,使用对象。维护对象的关系。

——/*类与对象的关系(鸡生蛋、蛋生鸡的关系),类就是对现实生活中事物的描述,对象:就是这类事物的,实实在在存在的实体,*/——

:  就是描述事物,就是定义属性(成员变量)和行为(function),回顾内存这部分知识,注意多引用指向同一个对象

注意:成员变量和局部变量的区别,存储区域、作用域,特点(图纸的颜色和汽车的颜色的区别)匿名对象:是对象的简写格式。使用情况:

1、当对对象方法仅调用一次时(new car().run();调用对象方法有意义,属性没意义),

2、匿名对象可以作为实际参数进行传递——凡是简化的都有局限性。

封装(encapsulattion):

隐藏(通过权限修饰符)对象的属性和实现细节,仅对外提供公共的访问细节。好处:将变化隔离、便于利用、提高重用性、提高安全性。封装原则:1、将不需要的内容都隐藏起来。2、把属性都隐藏,提供公共方法对其访问————(招聘一个员工,分配下去任务后,只要结果,不要过程,程序员自己的开发心酸什么的都隐藏,类似于电脑主机,将芯片。显卡。主板。风扇封装,对外提供插口访问主机功能)

Private:私有,权限修饰符,,用于修饰类中的成员(成员变量、成员function),私有只在本类中有效。一个成员变量,通常有两个方法(一个get,一个set),可以通过逻辑语句控制输入的数据,来实现封装,增强健壮性。注意:私有仅仅是封装的一种表现形式。

          构造函数:

a) 特点: 1、函数名与类名相同(包括大小写)。2、没有返回值。3、没有return语句。

b) 作用:对对象进行初始化(对象一建立,就会调用与之对应的构造函数)

c) 注意:1、默认空参的构造函数的特点(自定义了构造函数后,默认构造函数就没了)。2、多个构造函数是以重载的形式出现的  3、构造函数不存在继承,也就没有覆盖,但是可以通过this(),或super()相互调用

构造代码快(定义不同对象共性的初始化内容)

a) 作用:给对象进行初始化

b) 对象一建立就运行,而且优先于构造函数。

c) 和构造函数的区别:构造代码块是给所有对象进行初始化,而构造函数是对对应的对象进行初始化

this关键字

a) 当局部变量与成员变量的名字相同时,前者隐藏掉后者,要用到this,代表所在函数所属(本)对象的引用。

b) This语句:用于构造函数之间的调用(ps:构造一个人,只有姓名。构造另一个人,同时赋予姓名和年龄。

               就可以通过this(name)调用另一个构造函数——)

c) This()语句只能定义在构造函数的第一行;因为初始化要先执行!!

static关键字:

是一个修饰符,只能用于修饰成员(成员变量、成员function),提取到另外一个内存空间,对象都可以直接调用, 省内存

特点: a)、随着类的加载而加载,随着类的消失而消失,生命周期最长;

b)、优先于对象的存在,不建议定义过多的静态变量。

c)、被所有对象调用。静态多了一种调用方式:类名 . 静态成员;

方法区(共享区、数据区):存放类中的方法、类中的共享数据。

类变量和实例变量的区别:

a、类变量随着类的加载而存在于方法区中,随着类的消失而消失,实例变量随着对象的建立而存在于对内存中。

b、类变量生命周期最长,实例变量随着对象的消失而消失。

静态的使用注意事项:

1)静态方法只能只能访问静态成员,非静态既可以访问静态也可以访问非静态,

2)静态方法中不可以定义this,super关键字,因为,静态优先于对象存在

静态的利弊:

                   对对象的共享数据进行单独存储,节省空间。可以直接类名调用。生命周期长,访问有局限性,静态只能访问静态

什么是主函数:public static void main(String[] args0主函数是一个特殊的函数,作为程序的入口,被JVM调用

主函数的定义:public、代表着该函数的访问权限最大。static、代表着主函数随着类的加载就已经存在了。void、主函数没有具体返回值(虚拟机接收到返回值会“害怕”)。main:不是关键字,但是可以被JVM识别。主函数是固定格式,可以被JVM识别。主函数也可以被重载。argument,主函数的参数用“ ”空格隔开。主函数的使用。

有意思的代码:

class MainDemo {public static void main(String[] args)//new String[]{String[] arr = {"hah","hhe","heihei","xixi","hiahia"};MainTest.main(arr);}}class MainTest{public static void main(String[] args){for(int x=0; x<args.length; x++)System.out.println(args[x]);}}//一个java文件可以有两个main函数,而且相互之间可以调用,编译后在运行时指定类名即可,还可以相互调用。


什么时候使用静态:

                    要从两方面下手,当对象有共享数据时定义静态变量。当功能内部没有访问到非静态方法时可以定义静态方法。每一个应用程序都有共性内容,可以将这些功能进行抽取,独立封装,以便复用。

静态的应用:

                工具类ArrayTool:getMax();getMin();swap();printArr();selectsort(); 工具类中的方法都是静态的,所以创建工具类对象没意义,这时可以将工具类的构造函数私有化,不让调用者建立对象,体现了代码健壮性

帮助文档制作:

             以后重要的代码都要制作帮助文档练手;java的说明书通过注释文档来制作。

              这是描述类:

/** 这是一个对数组操作的工具类,该类中提供了最值获取,排序

@author 张三 

@version 1.1

*/

接下来描述功能,记住,凡是public修饰符的功能都用文档描述,因为都可以被文档注释工具获取,

/** @param (代表参数)arr代表接受一个arr的数组 @return 会返回最大值什么的*/

具体的特殊字符可以翻阅API,eclipse可以很快生成

Javadoc.exe(文档编译工具)

javadoc -d c:\ -author -version (表示要在c盘的根目录生成帮助文档,附带作者和版本号。

注意:被注释的类必须是public的权限 )

一个类中的默认构造函数的权限跟所属的类的变化而变化,不写就是默认的,空参的不是默认的

静态代码块(StaticCodeDemo):

                   格式:static{},特点:随着类的加载而执行,只执行一次;用于给类进行初始化,优于主函数

                  学习静态代码块要注意各个部分的执行顺序(代码块);

对象初始化过程在内存中是怎么样的?

1、默认初始化(成员变量加默认值)。

2、显式初始化(成员变量被赋值)

3、构造代码块执行。

4、构造函数初始化。

设计模式:

其实是从建筑学学习得来的,解决问题最有效的办法,23种通用模式。

单例设计模式解决一个类在内存中只存在一个对象(保证对象唯一性)。

             想要保证对象唯一性:

1、为了避免其他程序过多建立该类对象,先控制,禁止其他程序建立对象 。

2、还为了让其他程序访问到该类对象,只好在本类中自定义一个对象。

3、为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。

            这三部怎么用代码体现:

1、将构造函数私有化。

2、在类中创建本类对象。

3、提供一个方法可以获取该对象(不能new对象,所以方法只能是Static,只有get没有set)。

          饿汉式(先创建对象),

class Single{private static Single s = new Single();private Single(){}public static Single getInstance(){return s;}}

懒汉式(调用时才创建对象,也叫做延时加载。不建议用懒汉式,因为单例就是要用对象,直接创建。

class Single{private static Single s = null;private Single(){}public static Single getInstance(){if(s==null){synchronized(Single.class){if(s==null)s = new Single();}}return s;}}

懒汉式可能会出现对象不唯一(a程序调用时判断为空时将要建立对象,cpu切换到另一个b调用时判断为null也要建立对象,

           当cpu又切换到a时,又建立一个对象,不安全)。

          解决懒汉式不安全的方法可以加同步锁(synchronized)但是低效。也可以用多线程解决,随后解决。

一个对象的初始化顺序:

        先加载静态代码块(没有被加载过)--->构造代码块------>父类的构造函数----->本类构造函数---->类的属性加载进堆内存

Person p = new Person("zhangsan",20);

该句话都做了什么事情?
1,因为new用到了Person.class.所以类加载器会先找到Person.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。
5,对属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的p变量。

-----------------------------------------------------------------

继承:

特点:

1、提高了代码的复用性。

2、让类与类之间产生关系,有了这个关系才有了多态 的特性。

                      注意:不要为了获取其他类的功能,简化代码才继承,一定要有继成 关系,所属关系是 is a;(不能为玩ipad管人家叫爹)。

3、Java语言中只支持单继承(有别于C语言)。

                       因为多继承容易带来安全隐患(父类多了, 功能相同的话,就会出现调用不确定性)。

ps:接口可以实现多继承

4、Java支持多层继承,object是每个类的超类,实现树形结构。

类与类之间的关系:

            聚集:has a .

集合:结合更紧密,例如身体中的一部分(手、肺)。不一定是继承

             聚合:一个球队有很多球员的关系。子父类中变量的特点:

                      加载子class文件的时候,先加载父类class文件。

  成员变量与局部变量的不同:1.作用域不同,成员变量在整个类中都有效,而局部变量只在离他最近的{}中有效;2,存储位置不同,成员变量位于堆内存,局部变量位于栈内存。

 

不同点

成员变量

局部变量

作用域

整个类中有效

离它最近的一对{ }内有效

内存中的位置

堆内存

栈内存

this与super:

1、如果子类出现非私有的同名变量时,子类要访问本类中的变量用this,子类要访问父类中同名变量,用super。

2、This和super的用法几乎一样。this代表本类对象的引用。super代表父类对象的引用。

覆盖:当子类继承了父类,沿袭了父类的功能,到子类中。但是子类虽具备了父类的功能,但是功能的内容却不一致,这时没必要定义新功能,而是使用覆盖,既保存了父类功能的定义,也实现了子类特有的方法。

(例如手机功能不断的发展,来电显示),在覆盖的同时又想保存父类的方法可以用super.show();

注意事项:

1、子类的方法的权限必须大于或等于父类才能覆盖,不然编译失败。

2、静态只能覆盖静态。

3、子父类方法要一模一样。

子父类中构造函数的特点:

new子类对象时,先加载父类构造函数,然后加载子类的, 原因在于子类的构造函数中默认的有隐式的super();来调用父类的构造函数。 子类中所有构造函数的第一行都是空参的super();  为什么子类一定要访问父类的构造函数:因为父类中的数据可以直接获取,所以子类建立对象时,需要首先查看父类是如何对这些数据进行初始化的,所以子类初始化时,要先访问以下父类的构造函数。 如果要访问父类特殊的构造函数,可以通过手动定义super语句的方式来获取。注意:super();同样要放在构造函数第一行;

        结论:子类中的所有构造函数,默认都会访问父类的空参的构造函数。因此,子类 的构造函数第一行都有一句隐式的 super()。

当父类没有空参的构造函数时,子类 必须手动通过super语句形式来访问父类中的构造函数。

  当然,子类的构造函数第一 行也可以手动指定this语句来访问本类中的构造函数。 子类中至少有一个构造函 数会访问父类中的构造函数。


final 关键字:可以修饰类、变量、函数。

特点:

1、被final修饰的类不可以被继承。

2、被final修饰的方法不能被覆盖。

3、被final修饰的变量是常量(成员和局部都可以被修饰)。

什么时候用final?

1、当描述一些事物时,一些数值出现值是固定的,不需要被改 变,名称全部用大写字母表示,如果多个单词组成,单词间通过下划线连接。

2、 Public static final (全局常量,java中有黑多这样的常量)

3、 内部类定义在类中的局部位置上时,只能访问该部分被final修饰的局部常量。

抽象类(abstract):

当多个类中出现相同功能,但是功能主体不同,这时可以向上抽取。这时值抽 取功能的定义,而不抽取功能主体。

特点:

1、抽象方法一定在抽象类中。

2、抽象方法和抽象类,一定被abstract修饰。

3、抽象类不可以通过new建立对象,因为调用抽象方法没意义(不可实例 化)、可以有构造函数,用于继承,也可以有静态方法。

4、抽象方法要被调用,必须被子类覆盖所有抽象方法后,建立子类对象用。

                     如果子类没有覆盖完父类的抽象方法,那子类还是抽象类。

            5、抽象可以强迫子类去实现某些功能。

                               比如老板提出需求,没有说明怎么实现,就是没有方法主体

                 练习:AbstractText.java

练习:获取一段程序运行的时间,lang 包中 system 类中public static long ——currentTimeMillis();

abstract class GetTime{public final void getTime(){long start = System.currentTimeMillis();runcode();long end = System.currentTimeMillis();System.out.println("毫秒:"+(end-start));}public abstract void runcode();}class SubTime extends GetTime{
public void runcode(){
               for(int x=0; x<4000; x++){System.out.print(x);}}}class  TemplateDemo{public static void main(String[] args) {//GetTime gt = new GetTime();SubTime gt = new SubTime();gt.getTime();}}

模板方法模式:

                 在定义功能时。功能的一部分是确定的,一部分是不确定的,而确定的 部分在使用不确定的部分,那么就将不确定的部分暴露出去(不一定抽象),交给子类 去完成,确定的部分final(不一定)。

                  一个方法善于分拆为多个方法。

       什么是模板:类似于现实中的各种模板,例如月饼,模子的花边,字是相同的, 月饼的馅却是不确定的。

接口(interface):

                  初期理解为特殊的抽象类,当抽象方法全是抽象是,可以定义为接口。

接口定义格式特点:

1、接口常见定义:常量(全局常量)、抽象方法

2、接口中的成员都有固定的修饰符:常量:public static final          方法:public abstract

虽然写的时候可以不加public 等等,不过不建议省略。

类与类之间是继承关系,类与接口是实现关系。Implements 关键字。父类中有非抽象 内容子类可以直接拿来用,而接口全是抽象,需要全部覆盖才能实现功能。

—— Interface编译后也是class文件。

—— 接口可以多实现,是对继承只能单继承的补充。可以同时继承还能实现接口, —— 顺序:先继承后实现接口。

—— 接口可以继承接口。

—— java只在接口与接口之间有多继承。

接口的特点:

1、接口是对外暴露的规则。

2、接口是程序的扩展。

3、接口可以用来多实现。

4、接口与接口之间可以多继承,用,隔开

5、类与接口是实现,而且一个类在继承的同时实现多个接口。降低了耦合性(讲好规则之后,可以分拆,同时开工,模块式开发)

interface Inter{public static final int NUM = 3;public abstract void show();}interface InterA{public abstract void show();}class Demo{public void function(){}}class Test extends Demo implements Inter,InterA{public void show(){}}interface A{void methodA();}interface B //extends A{void methodB();}interface C extends B,A{void methodC();}class D implements C{public void methodA(){}public void methodC(){}public void methodB(){}}class InterfaceDemo {public static void main(String[] args) {Test t = new Test();System.out.println(t.NUM);System.out.println(Test.NUM);System.out.println(Inter.NUM);
}}

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

多态:

           某种事物具有多种表现形式。人有男人和女人。覆盖和重载都是多态的表现。

多态的体现:父类的引用指向了自己的子类对象。父类的引用也可以接受子类的对象。提到了反射。

多态的前提:必须是类与类之间有关系,要么继承,要么实现。

通常还有一个前提:存在覆盖。

多态的好处:多态的出现,大大提高了程序的扩展性。

多态的弊端:只能使用父类的引用,访问父类中的成员。 Animal a = new cat();// 类型转换,向上转型,自动完成。

Cat c = (cat)a; // 想要调用猫的特有方法时,可以用向下转型:强制将父类的应用,转成子类对象。

给我一只动物,给个猫给个狗也行。要是要个猫,给个狗就不行。千万不要将父类对象转换成子类类型。

我们能转换的是:父类引用指向子类对象时,该类型可以被引用,可以被强制转换,多态自始至终是子类对象的变化。

经典例子:

父亲,儿子都是教师,父亲教工商管理,儿子教java的功能,儿子有特定的方法,看电影。毕姥爷,毕老师,胡子,大衣、、

Classcastexception类型转换异常。实例对象.instanceof(类);用来判断对象的属性。

多态的出现代码中的特点(多态使用的注意事项):

多态非静态成员函数

在编译时期:参阅引用型变量所属的类中是否有调用方法。如果有,编译通过;如果没有则失败。

在运行时期:参阅所属的类中是否有调用的方法。

简单总结就是:编译看左边,运行看右边。

面试会遇到的问题:

多态中,成员变量的特点:无论编译还是运行,都参考左边(引用型变量所属的类)。

多态中,静态成员函数的特点:同上。因为先加载,不属于对象。

class Fu{static int num = 5;void method1(){System.out.println("fu method_1");}void method2(){System.out.println("fu method_2");}static void method4(){System.out.println("fu method_4");}}class Zi extends Fu{static int num = 8;void method1(){System.out.println("zi method_1");}void method3(){System.out.println("zi method_3");}static void method4(){System.out.println("zi method_4");}}class  DuoTaiDemo4{public static void main(String[] args) {
           

Fu f = new Zi(); System.out.println(f.num);//打印室父类的num = 5 f.method1(); //f.method3();//编译报错 f.method4();//父类方法没有被覆盖 f.method2(); System.out.println( "------------------------"); Zi z = new Zi(); z.method4();//静态方法,没有覆盖,用eclipse时,用对象调用时会警告

z.method1(); z.method2(); z.method3();

 
 
         }
/*显示结果  * 5zi method_1fu method_4fu method_2------------------------zi method_4zi method_1fu method_2zi method_3*/
}

多态的主板示例:

PCI接口,主板、网卡、声卡、debug卡

接口开发模式,从第collection col = new ArrayList();//接口的引用指向子类对象。提高程序健壮性和扩展性

多态的扩展示例:

数据库的操作:

1)连接数据库 (JDBC Hibernate框架连接)

2)操作数据库(c r u d )

3)关闭数据库连接

 

object:

超类,包含所有对象都有的功能。Java认为所有对象都具备比较性,equals方法比较的是哈希值。

让类可以比较的话不用再定义新的功能,可以直接覆盖超类的方法。

class Demo //extends Object{private int num;Demo(int num){this.num = num;}public boolean equals(Object obj)//Object obj = new Demo();{if(!(obj instanceof Demo))return false;Demo d = (Demo)obj;return this.num == d.num;}/*public boolean compare(Demo d){return this.num==d.num;}*/public String toString(){return "demo:"+num;}}class Person {}class ObjectDemo {public static void main(String[] args) {Demo d1 = new Demo(4);System.out.println(d1);//输出语句打印对象时,会自动调用对象的toString方法。打印对象的字符串表现形式。Demo d2 = new Demo(7);System.out.println(d2.toString());//Demo d2 = new Demo(5);//Class c = d1.getClass();}}

内部类:

  内部类的访问规则:

1、内部类可以访问外部类的成员(因为outer.this.成员变量),包括private的。

2、外部类要访问内部类,要先建立内部类对象(格式: 外部类.内部类 名字 = new 外部类.内部类();)。

3、内部类在外部类成员位置上时可以被private修饰,用 来封装。

4、内部类被static修饰后跟静态用法一样(不能访问非 静态变量、因为没有super和this)

5、当内部类中的定义了静态成员,该内部类必须是static

6、当外部类中的静态方法访问内部类时,内部类也必须 是static的

7、内部类中要访问局部变量,需要被声明为final

内部类什么时候用

当描述事物时,事物的内部还有事物,该事物用内部类来描述(比如人类,人内有各种器官),因为内部类在使用外部类的内容

内部类定义在局部时:

1、不能被成员修饰符修饰。

2、可以直接访问外部类成员,因为还持有外部类引用,但是不可以访问局部变量,只能访问final修饰的局部类。

3、在其他的外部类中部内new出内部类

匿名内部类:

1、匿名内部类其实是内部类的简写格式。

2、定义匿名内部类的前提:内部类必须是继承一个类或者实现接口

3、匿名内部类格式:

     new 父类或者接口(){定义子类内容}

4、匿名内部类就是匿名的子类对象,而且这个对象有点胖。可以理解为 带内容的对象。

5、匿名对象只能调用一次。

6、匿名内部类中的方法,最好不要超过三个。