Java中对象及其三大特征(封装,继…

1对象

1.访问对象成员

1.引用对象的成员变量

对象名.变量名

 

2.引用对象的成员方法

对象名.方法名(参数)

Vector v = new Vector();

v.addElement(“hello world”);

int[] a= {1, 2, 3, 4, 5}; 

int size = a.length;

System.out.println();

2.对象内存结构

1.创建对象将在JVM堆内存中开辟对应的成员变量内存存储空间,并对其进行初始化值的设定

2.所有的对象均存在于堆内存中,即便是static修饰的对象,内存存储位置也在堆内存,只是外部引用指向该位置

3.对象内存回收

1.对象的引用一旦不存在,该对象所占用的内存空间将永远不会被JVM访问到,该空间即变为垃圾内存,垃圾内存可以通过JVM自动回收的方式进行清理,也可以由程序员手工清除,具体的操作步骤详见System类中的gc方法

3.存在引用的对象内存空间将永远不被回收,如果内存中存在的此类对象过多,将造成内存不足的情况发生

4.对象作为方法的参数

1.类是一种数据类型,在进行方法参数设计时,可以为类传递对象作为参数,即对象作为方法的参数

2.对象作为方法的参数与基本数据类型作为方法的参数不同,基本数据类型传递的数据为对应的值,而对象作为方法的参数传递的是对象内存空间的引用

5.对象作为方法的返回值

1.类是一种数据类型,在进行方法返回值的设定时,可以将该类型作为方法返回值类型,此时方法返回的结果应为一个对象或null

2.对象作为方法的返回值与对象作为方法的参数十分相似,返回的也是该对象的引用

6.数组对象

数组在进行内存空间的创建时,占用的内存空间位于堆内存范围内,数组可以看做是一种特殊的对象,操作数组同样也是使用引用的格式来进行

 

7.对象数组

对象数组是一种特殊的数组,即数组中保存的元素是对象,在数组的内存表示格式中,对应的值不再是一个基本数据类型对应的二进制表示形式,而是一个对象的引用地址

8.This

1.为加强程序的阅读性,在类的实例方法中,为每一个实例变量或实例方法的引用前面添加this关键字,指代该调用使用的是当前类的实例

2.This关键字可以理解为成员的调用者对应的内存空间,简单来说A对象调用function(),在方法中所有的this指代的就是A对象,如果换B对象调用该方法,所有的this指代的就是B对象

3.this关键字在某些情况不能省略

4.This作为对象的默认引用有两种情形:

1.构造器中引用该构造器正在初始化的对象。

2.在方法中引用调用该方法的对象。

This关键字最大的作用就是让类中的一个方法,访问该类里另一个或Field.

9.匿名对象

匿名对象即没有名称的对象,也可以称为没有引用的对象,匿名对象仅在创建时有效,在其内存空间被使用完毕前,如果没有对其进行引用,则匿名对象将永久性成为垃圾内存

10.方法的所属性

Java语言中方法的所属性主要体现在如下几个方面:

1.方法不能独立定义,方法只能在类体里定义。

2.从逻辑定义上来看,方法要么属于该类本身,要么属于该类的一个对象。

3.永远不能立执行方法,执行方法必须使用类或对象进行调用。

11面试题

Person p = new Person();他在内存中做了哪些事?

1.将Person.class文件加载到内存中;

2.在堆内存中创建一个对象Person;

3.把Person中的属性进行默认初始化;

4.把Person中的属性进行显示初始化;

5.调用构造代码块(如果没有,不执行这个操作)

6.调用构造函数进行初始化;

7.在栈内存中声明Person类型的变量p;

8.把堆内存的地址(引用)赋给栈内存中p。

 

 

2面向对象特征—封装

1.封装的概念

封装即对外隐藏对象的内部具体实现,并开放出若干个可以操作的入口来访问数据

 

1.封装即对要操作的实体进行隐藏,使原始功能对外不可见,通过其他方法间接的操作真实的实体

2.日常生活中的各种电器的遥控器、银行的密码锁、指纹识别系统等均为封装的体现

 

2.封装的实现原理

1.Java语言中为实现对实体的封装,可以对类内的成员进行私有化(private)声明,使其功能对外不可见,然后为其提供对应的访问器,对原始被封装的实体进行操作

2.访问器分为两种

获取访问器

修改访问器

3.封装的标准实现(一)

1.为在Java编程人员建立一种快速的数据访问安全统一标准,对封装进行了格式的严格规定

2.封装通常是对成员变量进行,成员方法也可以使用,但是通常意义不大

3.class Person{

              private String name;

              public void setName(String name){

                     this.name = name;

              }

              public String getName(){

                     return this.name;

              }

       }

4.封装的标准实现(二)

1.私有化所有的实例变量

2.为实例变量提供一个获取方法,无参数,返回值类型为该实例变量的类型

       声明为public,方法体返回该实例变量的值

              get变量名 

              name   getName

              age         getAge

              当数据类型给boolean时,获取的方法改名为  is变量名

              getter方法

             

3.为实例变量提供一个修改方法,参数为一个,类型是该变量的类型

       声明为public,方法体不过返回,只对成员变量进行值得修改

              set变量名

              name       setName

              age         setAge

              setter方法

面向对象特征—继承

1.继承概述

继承描述的是一种类与类之间的关系

通过继承可以减少模型内部结构的重复描述,加强代码的复用性

 

2.继承基本概念

1.父类/超类/基类:类B继承类A,称类A为父类

2.子类:类B继承类A,称类A为子类

3.顶层父类:Object

3.继承语法结构

语法结构:

       class 子类名称 extends 父类名称{

       }

4.继承作用

1.子类可以使用父类的成员。

子类可以使用父类中已有的成员变量————增强代码的复用性

子类可以使用父类中已有的成员方法————增强代码的复用性

2.子类可以定义父类中没有的成员。

3.子类可以对父类中已有的成员进行重新定义

子类可以保留父类已有的成员变量进行重新定义

保留父类已有的成员变量名,其他设定可以随意更改

子类可以对父类已有的成员方法进行重新定义——————(重写/覆盖)

子类可以使用实例方法覆盖父类的实例方法这个过程叫做重写。

    (子类使用静态方法覆盖父类的静态方法不叫重写,叫做子类隐藏了父类的静态方法)

                                                                               

5.重写(override)

1.重写是指子类对父类中已有的实例方法进行重新定义,称子类对父类的指定方法进行重写

2.重写只发生在继承关系中,重写描述的是子类方法对父类方法的关系

3.重写时子类重写的方法访问控制权限必须大于父类的访问控制权限

 

方法的重写要遵循“两同两小一大”规则,

“两同”:方法名相同,形参表列相同;

“两小”:1.子类的方法返回值类型应比父类方法返回值类型更小或者相等;

2.子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;

“一大”:子类方法的访问权限应比父类方法的访问权限要大或者相等。

覆盖方法和被覆盖方法要么是都是类方法要么都是实力方法,不能一个是类方法,一个是实例方法

※重载和重写

重载主要发生在同一个类的多个同名方法之间,重写发生在子类和父类的同名方法之间。当然,父类方法和子类方法之间也可能发生重载,因为子会获得父类的方法,如果一个子类定义了一个和父类方法相同的方法名,但参数列表不同的方法,就会形成子类方法和父类方法的重载。

6.重写误区

1.静态方法的覆盖称为子类隐藏了父类的静态方法,而不是重写了父类方法

2.父类的私有方法,子类是无法继承的,因此父类私有方法不能被重写

javap指令

3.实例方法在重写时不能添加static修饰符,静态方法被重新定义时不能定义为非静态的方法

7.重写的应用

当一个类开发完成,后期维护过程中,发现其功能已经过时,需要对其进行维护,添加一些新的功能,但是旧的功能如果被修改,可能导致其他功能连带失效,为了避免该现象,在不惊动原始功能的基础上,对其进行功能的扩展,即可以利用重写的特点进行,这一方式即设计模式中的装饰模式的雏形。

8.Super

子类对父类的某些实例方法进行覆盖后,在子类中将无法直接调用父类被覆盖的方法,可以通过super关键字,对父类的成员进行引用

super.父类成员变量

super.父类成员方法

如果在某个方法中访问名为 a 的Field,但没有显式指定调用者,则系统查找a的顺序为:

1.查找该方法中是否有名为a的局部变量;

2.查找当前类中是否包含名为a的Field;

3.查找a的直接父类中是否包含名为a的Field,依次上溯到a的所有父类,直到java.lang.Object类,如果最总不能找到名为a的Field,则系统会出现编译错误。

9.最终方法

1.如果父类中的方法不允许被它的子类重写,可以将其声明为最终方法,表示该方法不允许被覆盖

2.final修饰符可以将一个方法定义为最终方法

3.最终方法不允许被重写

10.最终类

1.对于一些常见的工具类或核心类,已经对其功能进行了详实的定义,不会再对其进行结构或功能的扩展,此时,为了避免其他类继承该类并对其功能进行扩展,可以声明当前类不允许被其他类所继承,通过关键字final实现

2.Final:对类进行final修饰符的添加,表明该类是一个最终类,不允许被继承

 

另外:(如果对一个成员变量用final修饰的话  该成员变量就变成为常量了。)

12.继承中的构造方法

1.创建子类对象时,首先要创建父类的对象,默认子类对象构造方法第一句会对父类对象的构造方法进行调用

2.当子类的构造方法没有显式的调用父类构造时系统会为每一个子类的构造方法第一行添加默认的super();来调用父类的构造方法,如果在子类的构造方法中声明了调用父类构造方法,则系统将不再为子类构造方法生成对父类构造方法的默认调用语句

 

不管是否显式使用super调用来执行父类构造的初始化,子类构造器总会调用父类构造器一次,子类构造器调用父类构造器分为以下几种情况:

1.子类构造器执行体的第一行使用super显式调用父类的构造器,系统将根据super调用里传入的实际参数列表调用父类的构造器。

2.子类构造器执行体第一行代码使用this显示式调用子类中重载的构造器,系统将根据this调用里传入的实际参数列表调用本类中另一个构造器,执行本类中另一个构造器时即会调用父类构造器。

3.子类构造器执行体中既没有super调用,也没有this调用,系统将会在执行子类构造器之前,隐式调用父类中无参的构造器。

  不管上面那种情况,当调用子类构造器来初始化子类对象时,父类构造器总会在子类构造器之前执行。

13.继承关系建立的基础

创建继承关系时,首先要确认所继承的父类是否存在可以访问的构造方法,如果父类不存在可以访问的构造方法,那么继承也将无法实现

14.继承关系内存结构

在创建子类对象之前,一定会先创建一个父类的对象,该父类的对象存在于子类对象之内,伴随着子类对象的消失而消失,此对象通过super关键字可以查找到其内存所在位置

 

15.继承中的修饰符限定

protected

       父类中可以通过为成员添加protected访问控制修饰符,限定哪些父类成员仅供子类继承

private

       父类中可以通过为成员添加private访问控制修饰符,限定哪些父类成员不被子类继承

public

       公共的成员不受任何约束,可以被继承

16.继承中的对象关系

子类继承自父类,子类将具有父类的形态,可以说子类也是父类的对象,可以使用关键字instanceof来判定某个对象是不是某种类类型

17.继承组合

1.Java语言中为了避免一个类继承多个类后造成成员的引用不明确,屏蔽了多继承的格式,2.Java语言中只存在有单继承模式,或通过逐级继承完成模拟多继承。

3.对于已经定义完成的类,Java虽然无法直接进行多继承,通过特殊的语法格式可以完成多继承的效果——类功能组合

 

为了保证父类有良好的封装性,不会被子类随意改变,设计父类通常应遵循如下原则:

1.尽量隐藏父类的内部数据。尽量把父类的所有Field都设置成private访问类型,不要让子类直接访问父类的 Field。

2.不要让子类可以随意访问,修改父类的方法,父类中那些仅为辅助其他的工具方法,应该使用priavate修饰,让子类无法访问该方法;

3.如果父类中的方法需要被外部类调用,则必须以public修饰,但又不希望子类重写该方法,可以使用final修饰符来修饰该方法;

4.如果希望父类的某个方法被子类重写,但又不希望被其他类自由访问,则可以使用protected来修饰该方法。

5.尽量不要在父类构造器中调用将要被子类重写的方法。

当系统试图创建Sub对象时,同样会先执行父类其父类的构造器,如果父类构造器中调用了被其子类重写的方法,则变成调用被子类重写后的方法。当创建Sub对象时,会先执行Base类中的Base构造器,而Base构造器中调用了test方法————并不是调用(1)号test方法,而是调用(2)号方法,此时Sub对象的name Field是null,因此引发空指针异常。

18 利用组合实现复用

 

多态

1.多态性

在继承关系中,一个子类对象不仅具有其本身类所具有的形态,还具有其父类对象所具有的形态,成该对象具有多种形态,这种关系叫做多态

 

JAVA引用变量有两个类型,一个是编译时类型,一个是运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋值给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。

 

相同类型的变量,调用同一个方法时呈现出多种不同的行为特征,这就是多态。

与方法不同的是,对象的Field则不具备多态性。

 

引用变量在编译时只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法,因此,编写JAVA代码时,引用变量只能调用声明该变量时所用类里的方法,例如:Object p = new Person();

代码定义了一个变量p,则这个p只能调用Object类的方法,而不能调用person类里定义的方法。

 

通过引用变量来访问其包含的实例Field时,系统会试图访问它编译时类型所定义的Field,而不是它运行时类型所定义的Field。

 

 

举例

 

class BaseClass

{

       public int book=6;

       public void base(){

              System.out.println("父类的普通方法");

       }

       public void test(){

              System.out.println("父类的被覆盖的方法");

       }

}

public class SubClass extends BaseClass

{

       //重新定义一个book实例Field,隐藏父类的book实例Field

       public String book="轻量级JAVA";

       public void test(){

              System.out.println("子类的覆盖父类的方法");

       }

       public void sub(){

              System.out.println("子类的普通方法");

       }

       public static void main(String[] args){

              //下面编译时类型和运行时类型完全一样,不存在多态

              BaseClass b = new BaseClass();

              System.out.println(b.book);

              //下面两次调用将执行BaseClass方法

              b.base();

              b.test();

              //下面编译时类型和运行时类型不一样,多态发生

              BaseClass p = new SubClass();

              //输出6-----表明访问的是父类的Field

              System.out.println(p.book);

              //下面调用将执行从父类继承到的base方法

              p.base();

              //下面调用将执行当前类的test方法

              p.test();

              //因为p的编译时类型是BaseClass

              //BaseClass没有提供sub方法,所以下面的代码编译时会出现错误

              //p.sub();

       }

}

 

 

2.引用变量的强制类型转换

强制类型转换时需要注意:

1.基本数据类型之间的转换只能在数值类型之间进行,这里所说的数值类型包括整数型,字符型和浮点型,但数值型和布尔类型之间不能进行类型转换。

2.引用类型之间的转换只能在具有继承关系的两个类型之间进行,如果是两个没有任何继承关系的类型,则无法进行转换。如果试图把一个父类实例转换成子类类型,则这个对象必须实际上是子类实例才行(即编译时类型为父类类型,运行时类型为子类类型),否则将在运行时引发ClassCastException异常。

 

3.面试题

 

class Father{

       int a = 1;

       Father(){                      //----------------------(1)

              show();                 //---------------------(2)将执行(3)的结果  son 0

       }

       void show(){

              System.out.println("father "+a);

       }

}

class Son extends Father{

       Son(){

              super();

              System.out.println("-----------------------");

              show();                        //---------------------------------------(4) son 10

       }

       int a = 10;

      

       void show(){

              System.out.println("son "+a);//----------------(3)  son 0

       }

}

public class Demo1{

       public static void main(String[] args){

              Father f = new Son();

       }

}

 

 

Java的子类不能获得父类的构造器?但子类构造器里可以调用父类构造器的初始代码块。

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值