JAVA基础知识1——堆栈、引用传递、static、多态、继承、接口

1.JVM(java虚拟机):
    Java 编译器会将java程序(高级语言)经过编译会形成hello.class文件(字节码文件),类加载到JVM里面后,JVM读取并处理class文件,执行引擎把字节码转为可执行代码(机器码),执行的过程,再把可执行代码转为机器码,由底层的操作系统完成执行。

针对于不同的操作系统平台,有不同版本的Java虚拟机,一个Java虚拟机实例在运行过程中有三个子系统来保障它的正常运行,分别是类加载器子系统, 执行引擎子系统和垃圾收集子系统。 如下图所示:

  1. 类加载器的子系统用来在运行时根据需要加载类。注意上面一句话中的“根据需要”四个字。在Java虚拟机执行过程中,只有他需要一个类的时候,才会调用类加载器来加载这个类,并不会在开始运行时加载所有的类。就像一个人,只有饿的时候才去吃饭,而不是一次把一年的饭都吃到肚子里。一般来说,虚拟机加载类的时机,在第一次使用一个新的类的时候。
  2. 由虚拟机加载的类,被加载到Java虚拟机内存中之后,虚拟机会读取并执行它里面存在的字节码指令。虚拟机中执行字节码指令的部分叫做执行引擎。就像一个人,不是把饭吃下去就完事了,还要进行消化,执行引擎就相当于人的肠胃系统。在执行的过程中还会把各个class文件动态的连接起来。
  3. Java虚拟机会进行自动内存管理。具体说来就是自动释放没有用的对象,而不需要程序员编写代码来释放分配的内存。这部分工作由垃圾收集子系统负责。

最后做一个总结:

  1. 虚拟机并不神秘,在操作系统的角度看来,它只是一个普通进程。
  2. 这个叫做虚拟机的进程比较特殊,它能够加载我们编写的class文件。如果把JVM比作一个人,那么class文件就是我们吃的食物。
  3. 加载class文件的是一个叫做类加载器的子系统。就好比我们的嘴巴,把食物吃到肚子里。
  4. 虚拟机中的执行引擎用来执行class文件中的字节码指令。就好比我们的肠胃,对吃进去的食物进行消化。
  5. 虚拟机在执行过程中,要分配内存创建对象。当这些对象过时无用了,必须要自动清理这些无用的对象。清理对象回收内存的任务由垃圾收集器负责。就好比人吃进去的食物,在消化之后,必须把废物排出体外,腾出空间可以在下次饿的时候吃饭并消化食物。

3.PATH:是操作系统的环境属性,指的是可以执行命令的程序路径;
   CLASSPATH:是所有*.class文件的执行路径,java命令执行的时候将利用此路径加载所需要的*.class文件 。使用public class定义的类,要求文件名称和类名称保持一致,在一个*.java文件之中只能存在一个public class;使用class定义的类,文件名称可以和类名称不一致,在一个*.java文件之中可以同时存在多个class定义,编译之后会产生多个*.class文件


4.   堆栈:    
    堆内存(heap):保存每一个对象的属性内容,堆内存需要用关键字new来开辟,对象没有对应的堆内存指向,将无法使用。
    栈内存(stack):保存的是一块堆内存的地址数值
    堆内存保存的是对象的真正数据,栈内存可以理解为保存对象的名称(Book bk)
    每一次使用关键字new都会开辟新的堆内存空间
    类属于引用数据类型,进行引用传递时,传递的是堆内存的使用权 
        
5.Java避免了C/C++之中复杂的指针关系,而使用了更为简单的引用方式来进行内存传递
   Java的数据类型:分为基本数据类型和引用数据类型
        基本数据类型:byte、short、int、long、float、double、char、boolean等
        引用数据类型:类(class)、接口(interface)、数组
        基本数据类型在被创建时,在栈上给其划分一块内存,将数值直接存储在栈上
        引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。
        基本数据不牵扯内存分配问题,引用数据类型必须要进行内存的开辟

6.引用传递(java精髓) :一块堆内存空间(保存对象的属性信息)可以同时被多个栈内存空间共同指向, 则每一个栈内存都可 以修改同一块堆内存空间的属性值。值传递和引用传递的区别(https://blog.csdn.net/zhzhao999/article/details/53449504?tdsourcetag=s_pcqq_aiomsg)(https://blog.csdn.net/bjweimengshu/article/details/79799485 

https://github.com/Snailclimb/JavaGuide/blob/master/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/%E7%AC%AC%E4%B8%80%E5%91%A8%EF%BC%882018-8-7%EF%BC%89.md关于java的值传递和引用传递,这2篇文章讲解的清楚

  • 值传递的时候,将实参的copy一份给形参。
  • 引用传递的时候,将实参的地址值copy一份给形参,传递的是地址的拷贝

也就是说,不管是值传递还是引用传递,形参拿到的仅仅是实参的副本,而不是实参本身。

 

第三个例子:提供了改变自身方法的引用类型

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4");
}
foo(sb); // sb 被改变了,变成了"iphone4"。

第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"。

重点理解为什么,第三个例子和第四个例子结果不同?

下面是第三个例子的图解:
图片说明 
builder.append("4")之后
图片说明 
下面是第四个例子的图解:
图片说明 
builder = new StringBuilder("ipad"); 之后
图片说明

7.封装: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
        使用private关键字进行封装
        使用setter和getter方法来对属性进行读写
   使用封装有四大好处:
        良好的封装能够减少耦合。
        类内部的结构可以自由修改。
        可以对成员进行更精确的控制。
        隐藏信息,实现细节。
        
8.package:定义本java文件中定义的类所在的包(文件夹)“."表示子目录
        import关键字用来导包,导入的时候包名后面加.*  表示引入这个包里面所有的类
        所有的类都应该放在包中,类名称是“包.类”
        通常一个*.java文件只定义一个类,且用public class来声明    
        
9.命名规则:类名的首字母大写;变量名和方法名的首字母小写,驼峰标识

10.重载:  指方法名相同,参数的类型或个数不同, 调用的时候将会按照传递的参数类型和个数来完成不同方法的重载
 
11.构造方法:构造方法可以为类中的属性初始化,构造方法的类名称相同,无返回值类型声明。
     如果类中没有明确的定义出构造方法,则系统自动生成一个无参的什么都不做的构造方法。构造方法可以重载
    
12.static: static属性、方法=公共属性、方法 全局变量       

  1. 从语法形式上看:成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
  2. 从变量在内存中的存储方式来看:如果成员变量是使用static修饰的,那么这个成员变量是属于类的,如果没有使用static修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。
  3. 从变量在内存中的生存时间上看:成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。
  4. 成员变量如果没有被赋初值:则会自动以类型的默认值而赋值(一种情况例外被 final 修饰的成员变量也必须显示地赋值),而局部变量则不会自动赋值。

    static修饰的方法称为类方法,无this指针。其他的就是实例方法。
        类方法可以使用类名称或实例化对象调用,而非static方法只能依靠实例化对象才可以调用    
        类方法内部不能直接调用非static属性、方法,只能调用static方法、属性
        非static方法可以直接访问static属性、方法
        当一个类中不需要保存属性时,可以将这个类中的方法全部定义为static,这样做可以节约内存空间
        类方法是属于整个类的,而实例方法是属于类的某个对象的。        
    由于类方法是属于整个类的,并不属于类的哪个对象,所以类方法的方法体中不能有与类的对象有关的内容。即类方法体有如下限制:
            类方法中不能引用对象变量;
            类方法中不能调用类的对象方法;
            在类方法中不能使用super、this关键字。(this表示当前类的对象,由static修饰的方法是类直接调用,不需要创建对象,所以不能用this)
            类方法不能被覆盖。
            
13.继承:通过继承子类拥有了父类的所有成员(成员变量和方法)    
        一个子类只能有一个父类,一个父类可以派生出多个子类
        使用extends关键字来进行继承

14.子类对象的实例化:
        当通过关键字new实例化子类对象时,会默认调用父类的无参构造方法,为父类对象实例化,
        而后才会调用子类的构造方法,为子类对象实例化。
           
15.访问权限:private  类内部
        :default  类内部  同一个包
        :protected类内部  同一个包  子类
        :public   类内部  同一个包  子类  任何地方
        对于class的权限修饰只可以用public和default
        
16.重写:在子类中可以根据需要对从基类中继承的方法进行重写
        重写方法必须和被写方法具有相同的方法名称、参数列表和返回类型
        重写方法不能使用比被写方法更严格的访问权限
        父类方法前加final关键字,则无法被复写
        
17.this:  代表使用该方法的对象的引用,可以看作是一个变量,他的值是当前对象的引用
        this可以调用本类属性和本类方法,如果本类(子类)没有指定的方法或属性,则去父类中查找是否存在
        调用本类中的构造方法时,放在程序首行
        
18.super: 使用super表示当前子类的父类对象,表示子类直接调用父类的属性的方法,不会查找本类定义
        super可以用来引用直接父类的实例变量。
        super可以用来调用直接父类方法。
        super()可以用于调用直接父类构造函数。
        
19.继承中的构造方法:
        子类的构造的过程中必须调用起父类的构造方法(来保证父类对象先实例化,子类对象后实例化)
        子类可以在自己的构造方法中使用super(aegument_list)调用父类的构造方法
            使用this(aegument_list)调用本类的另外的构造方法
            如果调用super,必须写在子类构造方法的第一行
        如果子类的构造方法中没有显示地调用父类的构造方法,则系统默认调用父类无参的构造方法
        this和super均必须编写在构造方法内的第一行,所以两者无法同时存在于同一个构造方法之内
        
       除非两个类之间是“is - a”的关系,否则不要轻易地使用继承。过多的使用继承会破坏代码的可维护性,当父类修改时,会影响所有继承他的子类,增加了程序维护的难度和成本。
      不要仅仅为实现多态而使用继承,如果类之间没有“is - a”关系,可以通过实现接口与组合的方式来达到相同的目的

23.对象转型(casting):
            一个基类的引用类型变量可以“指向”其子类对象
            一个基类的引用不可以访问其子类对象新增加的成员(属性和方法)
            可以使用引用变量instanceof类名来判断该引用型变量所“指向”的对象是否属于该类或该类的子类
            子类的对象可以当作基类的对象来使用称作向上转型(upcasting),反之向下转型(downcasting)
            例:Object obja = new Book(); //upcasting
                Object objb = "hello";    //upcasting
                Book b = (Book) obja;      //向下转型
                String s = (String)objb;  //向下转型
            向上转型:目的是参数的统一
        抽象类和接口的对象都是利用对象多态性的向上转型,进行接口或抽象类的实例化操作

24.多态: 
    方法的多态性:重载与覆写
    对象的多态性:父子类对象的转换
        在程序执行期间判断所引用对象的实际类型,根据其实际类型调用其相应的方法
        继承是子类使用父类的方法,而多态则是父类使用子类的方法
        要求:  1.要有继承
                2.要有重写
                3.父类引用指向子类对象

对象多态性核心概念:
        如果抽象类或接口中的抽象方法被子类覆写了,那么实例化这个子类时,所调用的方法一定是被覆写过的方法
        即方法名称以父类为标准,而具体的实现需要依靠子类实现

25.抽象类/方法:   抽象类专门用来当父类,其作用类似一个“模板”
                使用abstract关键字定义
                利用抽象类可以使用abstract关键字明确定义子类需要重写的方法,即抽象方法
                含有抽象方法的类必须被声明为抽象类,抽象类必须被继承,抽象方法必须被重写
                在定义抽象类时,类中可以不定义抽象方法
                抽象类不能被实例化,必须通过对象的多态性进行实例化操作
                抽象方法只需声明(不需要加{}),而不需实现(不需要定义方法体)

26.final: 可以定义类、方法、变量
        使用final定义的类不能被继承,不能有子类
        使用final定义的方法不能被重写(就是说子类的方法中不能用和父类相同名称的方法,但如果这个final方法被private修饰,则此方法对子类不可见,子类不能覆盖。所以可以有同名方法,因为子类方法和父类方法是两个方法。)
        使用final定义的变量不能被修改,是常量
            
27.接口:    接口是抽象方法和常量值的定义的集合   
        使用interface关键字来定义        interface Singer
        接口是一种特殊的抽象类,这种抽象类中只包含常量和抽象方法
        “实现”类似于继承,用implemenst关键字来实现,接口必须被子类实现
        如果一个类实现了某个接口,那么这个类必须重写这个接口中的所有方法,否则就必须声明为抽象类
        class Student implement Singer   //Singer是一个接口
        如果父类实现了某个接口,那么子类自然也就实现了该接口,子类不必再显式地使用关键字implements声明实现这个接口
        多个无关的类可以实现同一个接口
        一个类可以实现多个无关的接口,接口主要用于解决单继承局限问题
        接口和接口之间可以继承
        接口具有多态性
        接口中的方法只有public一种访问权限
        接口可以多重实现

28.使用instanceof关键字,可以判断对象属于哪个类    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章