Java面向对象

今天,又去面了越秀金科,怎么说?我发现自己的 一个问题就是明明问的东西其实自己是想得通的,为什么就不能完整的表达出来呢?而且回答的很没有方向感,很没有条理。真的是很简单的一个问题:如何理解Java面向对象?到底回答的一个思路是什么?我找到了下面这一篇。

Java面向对象详解 - OpenFire_ - 博客园

区分面向对象和面向过程

面向过程就是指分析出解决问题所需要的步骤,然后用函数把这些步骤一步步实现,使用时依次调用即可。例如,一辆汽车用面向过程的思路去想,是如何启动汽车、如何起步、加速、熄火、刹车等操作,在这里汽车不是我们关心的,我们关心的是事件。

面向对象是把构成问题的事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。还是拿汽车来说,用面向对象的思想去看,我们关注的主体是汽车,汽车的发动机、传动箱、变速箱、刹车等属性是汽车这个对象本身所具有的,做任何操作只需要告诉汽车即可。

如何理解面向对象?

面向对象的内容主要包括:类、对象和面向对象的三大特征(封装、继承和多态)

类就是具有相同属性和方法的一组对象集合,它为属于该类的所有对象提供了统一的抽象描述。

对象就是类的实例,系统会为对象分配内存。当一个对象没有引用指向它时,该对象为无用对象,java的垃圾收集器会自动扫描动态内存区,把无用对象全都收集起来并释放内存。

封装:封装是面向对象编程的核心思想,类把对象的属性和行为封装起来,隐藏其内部状态。这就是封装的思想。

继承:当一个类的属性与行为均与现有类的相似,属于现有类的一种,这个类可以定义为现有类的子类。相反,如果多个类具有相同的属性与行为,我们可以抽取出共性的内容并定义成父类,这时再创建相似的类时只要继承父类即可。

多态:多态的特征是具有多种形态,具有多种实现方式。或者同一个接口,使用不同的实例会执行不同的操作。例如,不同的运动器材搭配球是不同的运动,有羽毛球运动,篮球运动,乒乓球运动等等,但我们只定义了一种器材搭配球而已,而后台又会集体判断是什么运动器材搭配球,从而得知是什么运动。这就是多态。

抽象与封装有何区别?

抽象是指从众多事物中抽取出共同的、本质的特征,而舍弃其非本质的特征。

封装则是指将抽象出来的数据和行为相结合,形成一个有机的整体,也就是类,其中数据和行为都是类的成员。private就是封装的一种体现。

封装是抽象策略的一部分,在我理解认为,抽象包括抽取出共性的、本质的内容和将其封装起来两部分,而封装则仅仅是体现出对象封装其内部状态,并对外隐藏的行为。

因此抽象才是我们更常用的术语,例如List接口是一个集合抽象,因为它把ArrayList,LinkedList等集合实现类中共同本质的东西抽取并封装起来。

接口和抽象类有何区别?

从语法层面来说:
(1)一个类只能继承一个抽象类,但可以实现多个接口
(2)抽象类的成员变量可以是多种类型,接口的成员变量必须要有public static final 修饰
(3)抽象类中可以含有静态代码块和静态方法,接口不可以
(4)抽象类可以提供成员方法的实现细节,接口的成员方法只能是public abstract。
从设计层面来说:
抽象类是对类的抽象,接口则是对行为的抽象。所以抽象类既能抽象成员变量,也能抽象成员方法,但接口只能抽象成员方法而不能抽象成员变量。
继承代表“是不是”的关系,实现代表“能不能”的关系。而抽象类只能被继承,接口只能被实现,因此抽象类的子类必然是抽象类的一种,而接口的实现类必然具有接口中所声明的能力。例如现在有飞机和鸟两个抽象类,飞机和鸟显然不是同一种类,但都会飞,因此把飞这个行为抽取出来封装在接口里,飞机和鸟如果实现了这个接口,则表示能飞,没有实现则表示不能飞。由于飞机和鸟具体有很多种类,比如飞机有战斗机,民用飞机,鸟有麻雀和老鹰等等,它们之间是继承关系,即表达成战斗机是飞机的一种,麻雀是鸟的一种。

权限修饰符之间的区别


11个java修饰词作用对象和所起到的作用

JVM的类装载机制

虚拟机把描述类的数据从class文件加载到内存(即从硬盘到内存),并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。这就是Java虚拟机的类装载机制。

其中解释一下JVM把HelloWorld.class变成Class对象的全过程
(1)类加载器的初始化


通过上面这个图我们可以知道AppClassLoader的父ClassLoader是ExtClassLoader,而ExtClassLoader的父ClassLoader是Bootstrap Loader。
Public class Test{ 
    Public static void main(String[] arg){ 
      ClassLoader c  = Test.class.getClassLoader();  //获取Test类的类加载器 
        System.out.println(c);  
      ClassLoader c1 = c.getParent();  //获取c这个类加载器的父类加载器 
        System.out.println(c1); 
      ClassLoader c2 = c1.getParent();//获取c1这个类加载器的父类加载器 
        System.out.println(c2); 
  } 

以上这个代码执行之后输出的结果是:
AppClassLoader
ExtClassLoader
Null
为什么最后不是Bootstrap Loader而是Null呢?因为Bootstrap Loader是用C++语言写的,但这是在Java环境下,因此逻辑上并不存在Bootstrap Loader这个类实例,因此输出为Null。

注意:同一个ClassLoader(如果是不同的ClassLoader,但其顶层类加载器相同,也视为同一个ClassLoader)加载同一个Class文件,只产生一个Class实例。两个不同的ClassLoader(其顶层类加载器不同)加载同一个Class文件,会产生两个Class实例。这种情况体现了双亲委派模型的好处。比如java.lang.Object类,由始至终都是启动类加载器(Bootstrap Loader)去加载,只产生一个Object实例。但如果用户自定义了一个Object同名类,并放在程序的classpath中,则这个Class文件是由AppClassloader加载产生了另一个Object实例,会使程序变得混乱。


(2)类的加载

类加载的动态性体现:一个应用程序总是由n个类组成,当启动Java程序时,JVM并不是一次性把所有的类加载进内存,而是先将能保证程序正常运行的基本API加载进JVM,其它的类在需要用到的时候再由JVM加载。这样做的好处是节省了内存的开销。

通过上图可以知道是通过AppClass装载器加载类文件的,但其实如果AppClass装载器的父装载器存在的话,是由其父装载器加载类文件的。如果不存在,则是由AppClass来执行装载操作
  • 装载:查找和导入Class文件
                         在装载阶段,虚拟机需要完成以下3件事情
                         (1) 通过一个类的全限定名来获取定义此类的二进制字节流
                         (2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
                         (3) 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。
                         虚拟机规范中并没有准确说明二进制字节流应该从哪里获取以及怎样获取,这里可以通过定义自己的类加载器去控制字节流的获取方式。
  • 链接:把类的二进制数据合并到JRE
                         校验:检查载入class文件数据的正确性

                         准备:给类的静态变量分配存储空间

                                     准备阶段是正式为类变量分配并设置类变量初始值的阶段,这些内存都将在方法区中进行分配,需要说明的是:
                                     这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中;这里所说的初始                                        值“通常情况”是数据类型的零值,假如:
                                      public static int value = 123;
                                      value在准备阶段过后的初始值为0而不是123,而把value赋值的putstatic指令将在初始化阶段才会被执行

                         解析:将符号引用转换成直接引用
  • 初始化:对类的静态变量,静态代码块执行初始化操作
注意:凡是加载类的过程中是通过指定ClassLoader对象来加载类的,一律不执行初始化
(1)ClassLoader loader = HelloWorld.class.getClassLoader();
          Class class = loader.loadClass("HelloWorld");
(2)Class class = Class.forName("HelloWorld",false,loader);
(3)Class class = Class.forName("HelloWorld");
(4)遇到new字眼的隐式装载
前三种情况都是显式装载,而且显式装载时凡是有指定ClassLoader对象的,不会执行该类的静态方法和静态代码块。但第三种情况就有执行类的静态方法和静态代码块。

下面是JVM的内存模型






通过一个例子形象说明一下什么样的数据存放在哪个区域内


java内存存储模型(句柄访问)


java内存存储模型(直接指针访问)

Java内存模型的原子性、可见性和有序性




其实这里就是从内存角度出发解释并发编程时出现的问题,我们要针对这些问题提出解决方案。

工作内存要操作主内存中的变量的过程中包括以下原子操作:read、load、use、assign、store、write。

因为线程之间要通过共享变量进行数据通信,但线程不是直接操作主内存中的引用,而是拷贝一个副本到工作内存中,对该副本引用进行操作,所以副本的值有变,而主内存的值并没变,所以值的改变在其它线程中并不可见,必须要同步到主内存中才可见,因此我们要保证可见性必须实现同步,而volatile、synchronized和final可以保证可见性。

volatile只能保证可见性,不能保证有序性,而synchronized既能保证可见性又能保证有序性。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值