[关闭]
@Mahdi 2018-02-26T20:39:59.000000Z 字数 8275 阅读 899

面向对象

java


类型,引用,对象,行为,多态,封装,继承

特点
- 面向对象就是一种常见的思想,符合人们的思考习惯
- 将复杂问题简单化
- 让曾经在面向过程中的执行者,变成了面向对象中的指挥者

面向过程强调的时过程(动作)

面向对象强调的时对象(实体)

类与对象的关系

java语言对现实生活中的事物进行描述,是通过类的形式来体现。

怎么描述呢?

对于事物描述通常只关注两方面。

一个是属性,一个是行为。

只要明确该事物的属性和行为并定义在类中即可。

对象:其实就是该类事物实实在在存在的个体

类与对象之间的关系?

类:事物的描述。

对象:该类事物的实例。在java中通过new来创建的。

注:对象内存图解

——————练习:平面上的一个点

成员变量与局部变量

1.
成员变量定义在类中,整个类中都可以访问。
局部变量定义在方法(函数),语句,局部代码块中,
只在所属的区域有效,不属于某个对象,
执行结束,变量就不再起作用了。

2.
成员变量存在于堆内存的对象中。
局部变量存在于栈内存的方法中。

3.
成员变量随着对象的创建而存在,随着对象的消失而消失。
局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。

4.
成员变量都有默认初始化值。
局部变量没有默认初始化值。

基本数据类型与引用数据类型参数传递

  1. //基本数据类型参数传递
  2. class Demo
  3. {
  4. public static void main(String[] args)
  5. {
  6. int x = 3;
  7. show(x);
  8. System.out.println("x="+x);
  9. }
  10. public static void show(int x)
  11. {
  12. x = 4;
  13. }
  14. }
  15. //引用数据类型参数传递
  16. class Demo
  17. {
  18. int x = 3;
  19. public static void main(String[] args)
  20. {
  21. Demo d = new Demo();
  22. d.x = 9;
  23. show(d);
  24. System.out.println(d.x);
  25. }
  26. public static void show(Demo d)
  27. {
  28. d.x = 4;
  29. }
  30. }

private关键字

private:私有,是一个权限修饰符。用于修饰成员。私有的内容只在本类中有效。

注意:私有仅仅是封装的一种体现而已。

构造函数

构造创建对象时调用的函数。作用:可以给对象进行初始化。

特点

1.函数名与类名相同

2.不用定义返回值类型

3.没有具体的返回值

创建对象都必须要通过构造函数初始化。

一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。

如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。

一般函数与构造函数

构造函数可以调用一般函数,一般函数不能调用构造函数

什么时候定义构造函数

细节

1.构造函数如果完成了set功能。set方法是否需要。

2.一般函数不能直接调用构造函数。

3.构造函数如果前面加了void就变成了一般函数。

4.构造函数中是有return语句的。

构造函数之间的调用以及this关键字

当成员变量和局部变量重名,可以用关键字this来区分。

this : 代表对象。代表哪个对象呢?当前对象。
       this就是所在函数所属对象的引用。
       简单说:哪个对象调用了this所在的函数,this就代表哪个对象。

this也可以用于在构造函数中调用其他构造函数。
注意:只能定义在构造函数的第一行。因为初始化动作要先执行。

static关键字

static的特点:

1.static是一个修饰符,用于修饰成员。

2.static修饰的成员被所有的对象所共享。

3.static优先于对象存在,因为static的成员随着类的加载就已经存在了。

4.static修饰的成员多了一种调用方式,就可以直接被类名所调用。类名.静态成员 。

5.static修饰的数据是共享数据,对象中的存储的是特有数据。

可不可以都定义成static??

成员变量与静态变量的区别

1.两个变量的生命周期不同。
成员变量随着对象的创建而存在,随着对象的被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。

2.调用方式不同。
成员变量只能被对象调用。
静态变量可以被对象调用,还可以被类名调用。

3.别名不同。
成员变量也称为实例变量。
静态变量称为类变量。 

4.数据存储位置不同。
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据.
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据.

静态使用的注意事项:
1,静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
2,静态方法中不可以使用this或者super关键字。
3,主函数是静态的。

注:内存图画画

静态什么时候用?
1.静态变量。
当分析对象中所具备的成员变量的值都是相同的 。
这时这个成员就可以被静态修饰。
只要数据在对象中都是不同的,就是对象的特有数据,必须存储在对象中,是非静态的。
如果是相同的数据,对象不需要做修改,只需要使用即可,不需要存储在对象中,定义成静态的。

2.静态函数。
函数是否用静态修饰,就参考一点,就是该函数功能是否有访问到对象中的特有数据。
简单点说,从源代码看,该功能是否需要访问非静态的成员变量,如果需要,该功能就是非静态的。
如果不需要,就可以将该功能定义成静态的。当然,也可以定义成非静态,
但是非静态需要被对象调用,而仅创建对象调用非静态的
没有访问特有数据的方法,该对象的创建是没有意义。

静态代码块

随着类的加载而执行,而且只执行一次

用于给类进行初始化

构造代码块

给所有对象进行初始化

构造函数是给对应的对象进行针对性的初始化

局部代码块

限定局部变量的生命周期

继承

继承的出现提高代码的复用性

让类与类之间产生了关系,给第三个特征多态提供了前提

java只支持单继承:一个子类只能有一个直接父类。

class SubDemo extends Demo{}//ok
class SubDemo extends Demo1,Demo2...{}//error

但java可以支持多实现:一个类可以实现多个接口

class SubDemo implements DemoListener1,DemoListener2...{}//ok

java同样支持多层继承,C继承B,B继承A,就会出现继承体系。

class A{}
class B extends A{}
class C extends B{}

什么时候定义继承呢?

当类与类之间存在所属关系的时候,就定义继承。xxx是yyy中的一种,xxx extends yyy

所属关系:is a 关系

注意:不要仅为了获取其他类中某个功能而去继承

在子父类中,成员的特点体现

1.成员变量
当本类的成员变量与局部变量同名用this区分
当子父类中的成员变量重名用super区分
this代表一个本类对象的引用
super代表一个父类空间

2.成员函数
当子父类中出现成员函数一模一样的情况下,会运行子类的函数
这种现象,成为覆盖(重写)操作(私有方法不可以被重写)。这是函数在子父类中的特性
函数两个特性:
    1).重载,同一个类中
    2).重写,子类中
重写注意事项:
    1).子类方法重写父类方法时,子类权限必须大于等于父类权限(父类private不行)
    2).静态只能覆盖静态,或被静态覆盖

什么时候使用重写?
当对一个类进行子类的扩展时,子类需要保留父类的功能声明
但是要定义子类中该功能的特有内容时,就是用重写。(手机升级)

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

在子类构造对象时,发现,访问子类构造函数时,父类也运行了。
为什么呢?
原因是:在子类的构造函数中第一行有一个默认的隐式语句。 super();

子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。


为什么子类实例化的时候要访问父类中的构造函数呢?
那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,要先看父类是如何对自己的内容进行初始化的。

所以子类在构造对象时,必须访问父类中的构造函数。 
为了完成这个必须的动作,就在子类的构造函数中加入了super()语句。

如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用父类中哪个构造函数。
同时子类构造函数中如果使用this调用了本类构造函数时,
那么super就没有了,因为super和this都只能定义第一行。所以只能有一个。
但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。


注意:supre语句必须要定义在子类构造函数的第一行。因为父类的初始化动作要先完成。

一个对象实例化过程:
Person p = new Person();

final关键字

继承的弊端,打破了封装性

final关键字:
1.final是一个修饰符,可以修饰类,方法,变量。
2.final修饰的类不可以被继承。
3.final修饰的方法不可以被覆盖。
4.final修饰的变量是一个常量,只能赋值一次。
为什么要用final修饰变量。其实在程序如果一个数据是固定的,
那么直接使用这个数据就可以了,但是这样阅读性差,所以它该数据起个名称。
而且这个变量名称的值不能变化,所以加上final固定。

写法规范:常量所有字母都大写,多个单词,中间用_连接。

抽象类

抽象:笼统,模糊,不具体。就是从多个事物中将共性的,本质的内容抽取出来。

抽象类:Java中定义没有方法体的方法,该方法的具体实现由子类完成,该方法就称为抽象方法,包含抽象方法的类就是抽象类。

抽象方法的由来:多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。

  1. abstract class Demo{
  2. abstract void show();
  3. }
  4. class DemoA extends Demo{
  5. void show(){
  6. Sop("showA"):
  7. }
  8. }
  9. class DemoB extends Demo{
  10. void show(){
  11. Sop("showB"):
  12. }
  13. }

特点:

细节:

1.抽象类中有构造函数吗?

有,用于给子类对象初始化

2.抽象类可以不定义抽象方法吗?

可以的,但是很少见,目的就是不让该类创建对象。
AWT的适配器对象就是这种累,通常这种类中的方法有方法体,但却没有内容。
  1. abstract class Demo
  2. {
  3. void show1(){}
  4. void show2(){}
  5. }

3.抽象关键字不可以和哪些关键字共存?

private 不行。抽象方法需要被覆盖
static 不行。还需要对象吗?
final 不行。不准覆盖?

4.抽象类和一般类的区别?

相同点:
    都是描述事物的,都在内部定义可成员
不同点:
    1.一般类有足够的信息描述
      抽象类描述事物的信息不足  
    2.一般类中不能定义抽象方法,只能定义非抽象方法。
      抽象类中可定义抽象方法,同时也可以定义非抽象方法
    3.一般类可以被实例化
      抽象类不可以被实例化

5.抽象类一定是个父类吗?

是的。因为需要子类覆盖其方法后才可以对子类实例化

接口

当一个抽象类中的方法都是抽象方法的时候,这时可以将该抽象类用另一种定义和表示,就是接口interface

对于接口当中常见的成员,而且这些成员都有固定的修饰符(就算不写,自动加):

由此得出结论,接口中的成员都是公共权限。

  1. interface Demo{//编译完还是class文件
  2. public static final int NUM=4//int NUM=4;
  3. public abstract void show1();//void show1();
  4. public abstract void show2();//void show2();
  5. }

类与类之间是继承关系,类与接口之间是实现关系

接口不可以实例化,只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。否则这个子类就是一个抽象类

  1. class DemoImpl implements Demo{}
  2. DemoImple d=new DemoImpl();
  3. d.NUM;//ok
  4. d.NUM=4;//error
  5. DemoImpl.NUM;//ok
  6. Demo.NUM;//ok

接口的特点:

接口与抽象类的区别

共性:都是不断抽取出来的抽象概念

区别1:抽象体现继承关系,一个类只能单继承
      接口体现实现关系,一个类可以多实现
区别2:抽象类是继承,是 is a 关系
      接口是实现,是 like a 关系
区别3:抽象类中可以定义非抽象方法,供子类直接使用
      接口的方法都是抽象,接口中的成员都有固定修饰符

举例,犬与导盲犬

多态

某一类事物的多种存在形态

class 动物{}
class 猫{}
class 狗{}
猫 x=new 猫();
动物 x=new 猫();//一个对象,两种形态

猫这类事物既具备了猫的形态,又具备着动物的形态。这就是对象的多态。

简单说:就是一个对象对应着不同类型

在代码中的体现:父类或者接口的引用指向其子类对象

  1. abstract class Animal{
  2. absrtact eat();
  3. }
  4. class Dog extends Animal{
  5. void eat(){
  6. sop("啃骨头");
  7. }
  8. void lookHome(){
  9. sop("看家");
  10. }
  11. }
  12. class Cat extends Animal{
  13. void eat(){
  14. sop("吃鱼");
  15. }
  16. void catchMouse(){
  17. sop("抓老鼠");
  18. }
  19. }
  20. Cat c=new Cat();
  21. Dog d=new Dog();
  22. method(c);
  23. method(d);
  24. public static void method(Animal a){
  25. a.eat();
  26. }

多态的好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容

多态的弊端:前期定义的内容不能使用(调用)后期子类的特有内容

多态的前提:1.必须有关系,继承,实现;2.要有覆盖

Animal a=new Cat();

在这里,进行了自动类型提升,专业讲就是向上转型,但是限制了子类特有功能的访问

如果非要访问子类特有功能,向下转型

Cat c=(Cat)a;

但是不能这样子转型

Animal a=new Animal();
Cat c=(Cat)a;

也不能这样

Animal a=new Dog();
Cat c=(Cat)a;//ClassCastException

注意转型,自始至终都是子类对象在做着类型的变化!!

判断类型,instanceof

成员变量在多态的特点

只看引用变量所属的类

  1. class Fu{int num=3;}
  2. class Zi{int num=4};
  3. Fu f=new Zi();
  4. f.num->3

成员函数在多态的特点:

简单说,编译看左边,运行看右边

静态函数在多态的特点:
只依赖其引用变量所属的类

内部类

  1. class Outer{//铁扇公主
  2. class Inner{//孙悟空
  3. }
  4. }

有什么用?
一般用于类的设计。
分析事物时,发现该类事物描述中还有事物,而且这个事物还在访问被描述事物的内容。这时就是还有的事物定义成内部类来描述。

  1. class Outer{
  2. private int num=3;
  3. class Inner{
  4. void show(){
  5. System.out.println("show run..."+num);
  6. }
  7. }
  8. public void method(){
  9. Inner in=new Inner();
  10. in.show();
  11. }
  12. }

内部类是对象特有数据时(成员类),访问外部类中内部类的成员:

Outer.Inner in=new Outter().new Inner();

内部类是对象共享数据时(静态类),访问外部类中内部类的成员:

Outer.Inner in=new Outter.Inner();

内部类是对象共享数据时(静态类),访问外部类中内部类的静态成员:

Outer.Inner.成员

注意:当内部类定义了静态成员,该内部类也必须定义静态

Outter.this与Inner.this ###

  1. class Outer{
  2. int num=3;
  3. class Inner{
  4. int num=4;
  5. void show(){
  6. int num=5;
  7. System.out.println(num);
  8. }
  9. }
  10. void method(){
  11. new Inner().show();
  12. }
  13. }

Object类

Object类是类层次结构的根类。每个类都是用Object作为父类。所有对象都实现这个类的方法。

equals()方法

指示其他某个对象是否与此对象“相等”。 其实比的就是引用!看源码
当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。

hashCode()方法

返回该对象的哈希码值。调用c语言实现,看源码!
由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

toString()方法

返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。

Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:

getClass().getName() + '@' + Integer.toHexString(hashCode())

JavaBean规范

它不是语法规范,是习惯性编程规范,用这个规范写的类使用方便。
1)必须有包
2)具有无参构造函数
3)setter和getter方法
4)必须实现序列化接口

包Package

权限问题

        public   protected    default    private
同一类中        ok         ok         ok           ok
同一包中        ok         ok         ok
子类当中        ok         ok                      
不同包中        ok
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注