zoukankan      html  css  js  c++  java
  • Java基础整理

    1、泛型:

    a)         提到参数第一时间想到的应该是定义方法时设置的形参,并且在调用这个方法的时候为该方法传递的实参。泛型其实就是类型化参数,顾名思义,就是将方法参数由原来的具体类型参数化。这就类似于方法的变量参数,只是在这里把类型也当成参数可变的,在后边调用这个方法的时候传入具体。

    b)         泛型的本质是为了再不创建新的参数类型方法的情况下,通过泛型指定的不同的类型来控制形参具体限制的类型。

    c)         泛型的特点:泛型只在编译阶段有效,在编译之后程序会采取去泛型化的措施,在编译过程中,虚拟机正确检验泛型结果后会将泛型的相关信息擦除,并且在对象进入和离开方法的边界添加类型检验和类型转换的方法,类型信息不会进入到运行阶段。

    d)         泛型的使用包括泛型类、泛型方法、泛型接口。

    2、  多态:

    a)         面向对象编程中的三大特性就是封装、继承和多态。

    b)         封装就是隐藏了类的内部实现细节,在不影响使用的情况下可以改变类的内部结构,这样也能保护数据,暴露给外界的只有对该对象的访问方法。

    c)         继承是为了实现代码的重用,只要是两个类之间满足IS-A的关系,就可以使用继承,但是需要注意Java中的继承的单继承,一个类只能继承一个类,换言之一个类只能有一个父类,同时继承也为多态的实现做了铺垫。

    d)         多态指的是在程序定义的引用变量所指向的具体对象类型以及通过该引用变量所发出的方法调用具体是那个具体对象中的方法在编译阶段是不确定的,只有在程序运行期间才能具体确定。

                             i.              面向对象而言,多态又分为编译时多态和运行时多态,其中编译时多态是静态的,主要是指方法的重载,可以根据参数列表的不同或者参数类型的不同来区分是不用的函数方法,然后通过编译就能变成两个不同的方法。运行时多态是动态的,是通过动态绑定来实现的,也就是我们所说的多样性。

                           ii.              实现多态的三个重要条件:继承、重写和向上转型。继承是指在多态关系中必须要有存在继承关系的子类和父类、重写指的是子类必须对父类中的方法进行重写、向上转型指的是在定义的时候需要将父类的引用指向子类的对象。

                          iii.              多态实现的方法:基于继承的实现机制主要通过在父类和继承该父类的一个或者多个子类通过重写父类中的一个多个方法来体现的、基于接口的实现是通过重写该接口中的方法的多个不同类来实现的。但是基于接口实现的多态比基于继承实现的多态有更好的灵活性。

    3、  反射:

    a)         Java反射机制是在程序运行中,对于任意一个类都能够获取这个类的所有属性和方法;对于任意一个对象都能够调用该对象的任意方法和属性,这种动态获取信息以及动态调用对象的方法和属性的功能成为Java的反射机制。(换言之反射就是把Java类中的组成部分映射成一个一个的Java对象)

    b)   当我们new一个对象的时候,JVM会为我们加载相应类的.class文件,Class对象的由来是将class文件加载入内存之后,虚拟机会为自动该对象创建一个对应的Class对象。一个类只能对应生成一个Class对象。

    c)         Class对象是在加载类时由Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了,所以Class没有公共构造器。

    d)         获取Class对象的三种方法:

                             i.              Class stuClass = stu1.getClass();Object类中有一个方法getClass;

                           ii.              Class stuClass2 = Student.class; 每个类都有一个class属性

                          iii.              Class stuClass3 = Class.forName("fanshe.Student"):必须是完整的包名.类名

    4、  Java.String类

    a)         String中用于存放字符的数组被声明为final只能赋值一次不能被更改。也就意味着String类不能被继承,所有的属性和方法都默认是final类,对String对象的操作都不会影响原对象,也就意味着所有的操作都会生成新的对象。

    b)         String类的特点:

                             i.              任何一个String对象在创建完成之后都不会再被改变

                           ii.              任何对String对象的操作如果返回的不是原来的字符串,实际上都会创建一个新的String对象

                          iii.              如果该String对象存放在方法区的常量池中,那么在程序中的任何地方相同的字符串字面常量都是同一个对象

                          iv.              String对象重写了equal方法,用于比较字符串的内容是否相等

    c)         字符串直接赋值的方法创建的String对象,会存放在方法区的常量池中,只开辟一块堆内存空间,不会产生垃圾

    d)         通过构造器方法创建的String对象在堆内存空间中会像一般的对象创建一样开辟内存空间,当创建多个同样的字符串的时候会开辟多个内存空间,并且不能够自动进入方法区的常量池,需要手动设置。所以一般在使用的时候都是用直接字符串赋值的方法创建String对象。

    e)         字符串不属于8中基本数据类型(byte、short、int、long、double、float、char、boolean),而是一种引用数据类型

    f)          字符串常量池:我们知道对象的创建是需要消耗大量的时间和空间的,因为创建的字符串一般都会经常使用,所以为了提高虚拟机的性能和减少内存开销,使用字符串常量池进行性能的优化,每当我们使用字符串直接赋值的方法创建String类的时候,虚拟机会首先检查字符串常量池中是否已经存在该字符串对象,如果存在就直接返回字符串在常量池中的引用,如果不存在就会创建该字符串对象并且将该字符串存入字符串常量池中。

    g)         Java.StringBuffer和Java.StringBuilder类的比较:StringBuffer和StringBuilder对象代表一组可改变的Unicode字符序列。

                             i.              可以使用StringBuffer来对字符串的内容进行动态操作,不会产生额外的内存开销。

                           ii.              StringBuffer对象的创建可以有几种常见的方法:构造一个不带字符串缓冲区的容量默认为16个字符的StringBuffer对象;构造一个指定初始容量大小的StringBuffer对象;构造一个带指定字符串的StringBuffer对象。

                          iii.              如果要想判断两个StringBuffer对象是否相等,应该先把这两个对象全部转换成String对象然后再比较是否相等。

                          iv.              StringBuffer的优势就是节省内存开销

                           v.              StringBuilder是在JDK5.0版本后引入的,可以理解为是StringBuffer的简单替换版本,用在字符串缓冲区被单个线程使用的情况,但是它的创建和使用几乎和StringBuffer的一样的,

                          vi.              StringBuilder是非线程安全的,StringBuffer是线程安全的

                        vii.              StringBuffer在JDK1.0中就有,但是在某些方法的实现上String Builder的速度要比StringBuffer快

    h)         Java中的常量池分为两类:静态常量池和动态常量池

                             i.              所谓的静态常量池就是.class文件中的常量池,里边不但包含字符串字面量,还包括类方法的一些信息,占用class文件的绝大部分空间;

                           ii.              所谓的动态常量池指的是Java虚拟机加载类之后,把.class文件中的常量池加载进内存中,并且保存在方法区,我们所说的常量池就是指运行时常量池。

    5、  对象的克隆:

    a)         在Java中所有的对象都是缺省的继承于Object类,在Object类中有一个方法clone(),这是一个native关键字修饰的方法,我们都知道使用native修饰的方法都是非Java语言实现的,因为Java程序都是在虚拟机上编译运行的,这个clone()方法的执行效率要高一点。需要注意的是clone方法是protected修饰的方法,如果对象需要使用,需要重写该方法。

    b)         为什么会使用到对象的克隆:需要拷贝的对象的可能包含已经被修饰过属性,但是使用new生成的对象属性都是初始化的值,所以当需要用一个对象保存当前对象的状态,就需要使用克隆来完成。相比较创建一个新的对象然后再依次为属性进行赋值会比较麻烦,而且clone方法是非Java语言实现的更接近于底层代码,运行效率比较高。通过clone()方法克隆的对象和原来的对象是两个相互独立的对象,互不干扰。

    c)         如何实现拷贝:拷贝又分为深拷贝和浅拷贝:

                             i.              在Java语言中数据类型分为基本数据类型和引用数据类型,引用数据类型属于比较复杂的数据类型,那么区分使用深拷贝和浅拷贝的关键点就是待拷贝对象中是否有引用数据类型,如果有就需要用深拷贝方法来克隆对象。

                           ii.              浅拷贝的一般步骤:

    l  被拷贝的对象需要实现Clonable接口,这是一个标记接口,里边不包含任何的方法

    l  待拷贝对象需要重写clone()方法,在方法中调用super.clone(),就能实现对象的浅拷贝。

    l  此时该方法返回的对象和原来的对象是相互独立的,指向不同的堆内存空间,是两个相互独立的对象。

                          iii.              深拷贝的一般步骤:

    l  因为深拷贝和浅拷贝的区别就是待拷贝对象中时候有引用变量的存在,那么关键就是如何解决引用对象的拷贝问题。如果在有引用类型的对象中使用浅拷贝的话,那么针对引用类型的对象拷贝的只是该引用对象的引用变量,两个变量其实指向的还是同一个对内存空间的同一个地址。没有起到真正拷贝的目的。

    l  举例来说:在一个student类中有一个引用类型的变量Address,那么我们要想实现对Student的拷贝,就先要把Address类实现Clonable接口,重写clone()方法,先保证这个对象能够实现浅拷贝(前提是这个对象中不包含引用类型的属性),然后在Student类中也实现Clonable接口,并且实现clone()方法,在这个方法中我们调用super.clone()返回一个Student的克隆对象,还在把这个对象的Address属性变量使用(Addrss)super.clone()进行赋值操作,只有这样,我们克隆的Student对象才真正实现克隆。

                          iv.              浅拷贝和深拷贝的比较:深拷贝和浅拷贝的关键区别就是待拷贝对象中时候包含引用类型的属性,如果有就需要使用深拷贝,简单来说就是深拷贝不单单对象的基本数据类型的属性会被拷贝,对象包含的成员变量也会被拷贝一份给克隆对象

                           v.              注意:如果引用类型的属性里边还包含有引用类型的属性,那么我们就需要把内层的引用变量也要进行实现Clonable接口并且重写clone方法,这样其实就会比较麻烦,针对这样的情况,我们一般会使用序列化的方法来实现对象的拷贝。

    6、  继承和接口的比较:

    a)         继承使用已有的类作为基础创建新类的过程;接口在Java语言中是一个抽象类型,是抽象方法的集合。

    b)         什么时候使用继承?什么时候使用接口?:如果类之间的关系存在IS-A的关系,我们可以考虑使用继承,真正判断是否使用继承的原则可以参考:我们是否需要子类到父类进行向上转型,如果需要我们就可以考虑继承,除此之外我们就要考虑使用接口。

    c)         继承的特点:

                             i.              Java语言中的继承是单继承,一个类只能继承一个父类

                           ii.              但Java语言支撑多继承体系

                          iii.              子类可以直接访问父类中的非私有属性和方法

                          iv.              对于构造器来说,子类只能调用父类的构造器,不能继承

                           v.              继承可以提高代码的复用率

                          vi.              继承是实现多态的前提条件

                        vii.              继承是一种强耦合关系

    d)         接口的特点

                             i.              一个类可以有实现多个接口

                           ii.              接口不能被实例化,只能被别的类实现

                          iii.              接口中是没有构造方法的,接口是抽象方法的集合

                          iv.              接口中不能包含一般的成员变量,除非是public static final关键字修饰的变量

    e)         继承中构造器的调用顺序:有继承关系的类在实例化的时候,构建实例的过程是从父类向外逐步扩散的,就是从父类开始一级一级的完成创建。在子类中没有声明构造器的时候,編譯器会自从为我们调用父类的无参构造器:前提是父类中必须有无参构造器,如果没有的话我们就要使用super()来显示的调用父类的构造器。必须放在类中的第一行代码,否则程序会报错。先初始化静态成员变量—>然后调用父类构造器–》再初始化非静态成员变量–>最后调用自己构造器

    f)          抽象类和接口的区别:

                             i.              Abstract修饰的类成为抽象类,抽象类本质是类,起到一个类定义模板的作用,里边可有普通方法,也可以有抽象方法,接口中只能是抽象方法,不能有具体的方法实现

                           ii.              抽象类和接口都是不能被实例化的

                          iii.              抽象类缺省的被定义为public,但是也可以定义为protected,但是不能第一位私有,继承抽象类的子类必须实现抽象类中的全部抽象方法,如果没有被全部实现,那么子类也需要被定义为抽象类

                          iv.              抽象类中的成员属性可以是各种类型,但是接口中的成员属性只能是public static final类型的。

                           v.              接口中不能含有静态代码块和静态方法,但是抽象类中可以存在

                          vi.              抽象类不能使用final修饰,因为抽象类就是为了让子类继承的

                        vii.               

    7、  异常

    a)         Java异常机制是Java提供的一种识别及响应异常错误的一致性机制。

    b)         Java异常机制使用的一些关键字:

                             i.              try:用于监听,把需要被监听的代码放在try代码块中,当try代码块发生异常的时候一场就会被抛出。在try代码块中发生异常之后,在该异常后边的代码将不会在被执行。

                           ii.              catch:用于捕获并且处理try代码块中抛出的异常。

                          iii.              finally:finally代码块总是会被执行。它主要用于回收在try代码块中打开的各种资源(数据库连接,网络连接以及磁盘文件等资源)。只有finally代码块执行完成之后才会返回来执行抛出的异常或者执行return语句。但是如果在finally代码块中使用了return或者throw等终止方法的语句,那么就不会再跳回执行而是直接结束。

                          iv.              throw:用于抛出异常

                           v.              throws:用在方法签名中,用于声明该方法可能会抛出的异常。

    c)        

    d)         Error:是程序无法处理的错误。表示运行的应用程序中出现了比较严重的问题。这样的大多数错误都是与执行的代码无关,而是运行程序的虚拟机出现的无法解决的错误。这些错误都是不可查的,因为这些错误都在应用程序的控制和处理能力之外。编译器也不会检查Error异常。当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误。程序本身无法修复这些错误的

    e)         Exception:是程序本身可以处理的异常。RuntimeException是在程序执行过程中被执行代码出现了逻辑错误才会抛出的异常。編譯器不会检查RuntimeException,如果代码出现了这样的异常,需要通过修改代码来解决。

    f)          Java语言可以抛出的错误或者异常有三类:被检查的异常(Checked Exception)、运行时异常(RuntimeException)、错误(Error),其中运行时异常和错误为不被检查的异常。可检查的异常是编译器要求必须处理的Exception类本身以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常。,如果不处理编译就不会被通过,运行时异常也需要通过修改代码来解决。

    g)         总体来说,Java规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error。

    8、  重载和重写的区别

    a)         重载和重写都是多态性的体现,

    b)         重载指的是在编译阶段的多态性,在同一个类中,同名的方法如果参数类型或者参数个数不同或者两者都不相同,但是重载对方法的返回值类型没有要求,可以相同也可以不同

    c)         重写指的是在运行时的多态性。它发生在子类和父类之间,当子类继承父类并且子类中的方法名和父类中的方法名、参数类型和参数个数以及返回值类型都相同(可以不相同但必须是父类返回值的子类)的时候。两个方法之间是重写关系

    9、  final、finally、finalize的区别?

    a)         final:如果一个类被声明为final,那么这个类不会再被别的类继承,也就不会再有子类,如果一个变量被final修饰,那么这个变量在初始化的时候就要被赋值,并且在以后的使用中只能读取,不能被修改,如果一个方法被final修饰的话,那么这个方法同样只能被使用,不能被子类继承

    b)         finally:使用在try…catch代码块的后面构造总是被执行代码块,里面存放的一般是在try代码块中被打开的各种系统资源(数据库连接资源、磁盘文件等),不管前面的代码时候出现异常,finally代码块中的代码总会被执行。

    c)         finalize:Object类中定义的方法,Java中允许使用finalize方法将在垃圾收集器将对象清楚之前做必要清除工作。该方法在垃圾收集器将对象清除之前调用,通过重写该方法可以执行整理系统资源或者执行其他的垃圾清理工作。

    10、              对内存溢出和内存泄漏的比较:

    a)         内存泄漏指的是在程序运行过程中虚拟机为该程序分配了内存空间,但是这部分内存空间没有被及时的释放,从而造成这部分内存空间在一定时间段是不可用的,这就是内存泄漏。

                             i.              常发性内存泄漏:会发生内存泄漏的代码经常被执行,没执行一次就会造成一次内存泄漏

                           ii.              偶发性内存泄露:发生内存泄漏的代码在特定的环境或者特定的操作下才会被执行。这就要求检测环境和检测方法对内存泄漏至关重要。

                          iii.              一次性内存泄漏:内存泄漏的代码只会被执行一次,或者由于算法的缺陷导致总有一块内存无法被正常释放。

                          iv.              隐式内存泄漏:程序在运行过程中不停的为对象分配内存空间,但是这些内存空间直到结束才能释放,严格的说这里没有发生内存泄漏,但是例如服务器一般连续工作几个月,这样就会造成内存耗尽的情况,所以这种情况称之为隐私内存泄漏

    b)         内存溢出指的是:程序要求分配的内存空间大小超过了系统能够提供的内存大小,就会造成内存溢出。

    c)         如何避免造成内存泄漏和溢出呢?

                             i.              尽早释放掉无用的对象

                           ii.              程序进行字符串操作的时候尽量使用StringBuffer代替String

                          iii.              尽量减少使用静态成员变量

                          iv.              尽量避免集中创建对象尤其是大对象,尽量使用流操作

                           v.              运用对象池技术以提高系统性能

                          vi.              不要再经常用到的方法中创建对象。

  • 相关阅读:
    topcoder srm 320 div1
    topcoder srm 325 div1
    topcoder srm 330 div1
    topcoder srm 335 div1
    topcoder srm 340 div1
    topcoder srm 300 div1
    topcoder srm 305 div1
    topcoder srm 310 div1
    topcoder srm 315 div1
    如何统计iOS产品不同渠道的下载量?
  • 原文地址:https://www.cnblogs.com/BaoZiY/p/11376359.html
Copyright © 2011-2022 走看看