java

java基础学习

多线程

IO

异常

反射

数组

基础

1.final关键字

  • 修饰数据

    对于基本数据类型:final使数值不变
    对于引用类型:final使引用不变, 也就不能引用其他对象,但是被引用的对象本身是可以修改的。

  • 修饰方法

    声明的方法不能被子类覆盖
    private方法隐式地被指定为final。如果在子类中的一个方法与父类的一个private方法相同,此时子类的方法不是覆盖了父类的方法,而是在子类中定义了一个新的方法。

  • 修饰类

    声明的类不能被继承

2 . static关键字

  • 修饰静态变量

    静态变量只在类初始化的时候赋值一次,在内存中只存在一份。
    类所有的实例都共享静态变量,可以通过类名直接访问静态变量。
    实例变量:每创建一个实例都会产生一个实例变量,它与该实例共生死

  • 修饰静态方法

    静态方法在类加载的时候就存在了,他不依赖任何实例,static方法必须实现,他不能是抽象的。

  • 修饰静态代码块

    静态代码块在类初始化的时候运行一次。

-静态内部类

内部类的一种,静态内部类不依赖外部类,且不能访问外部类的非static变量和方法。

-静态导包

-变量赋值顺序

静态变量的赋值和静态语句块的运行优先于实例变量的赋值和普通语句块的运行,静态变量和静态语句块的运行取决于他们在代码中的顺序。

3 . Object通用方法

  • equals()

equals() 与 ==的区别

对于基本数据类型,使用==判断两个值是否相等,基本类型没有equals()方法。
对于引用类型,== 判断两个实例是否引用同一个对象,而equals()判断引用的对象是否等价。
  • hashCode()

    hashCode()返回散列值,而equlas()判断两个实例是否等价。等价的两个实例散列值一定相等。但是散列值相等的两个实例不一定等价。
    在重写equals()方法时,也要重写hashCode()方法,保证相等的两个实例散列值也相等
    
  • toString()

    默认返回ToStringExample@562216c这种格式,其中@后面的值为散列码的无符号十六进制表示。
    
  • clone()

    clone()是object的受保护的方法,如果一个类不显示地去覆盖clone()就没有这个方法。
    类重写clone()方法首先要实现cloneable接口,否则会抛出CloneNotSupportException,clone()方法并不是cloneable接口定义的方法,Cloneable接口只是规定。
    深拷贝:拷贝实例和原始实例的引用类型引用同一对象。
    浅拷贝:拷贝实例和原始实例的引用类型引用不同对象。
    使用clone()方法来拷贝一个对象即复杂又危险,最好不要使用clone(),可以使用copy构造函数或者拷贝工厂来拷贝一个对象。
    

4 . 继承

  • 访问权限

java中定义了三个访问修饰符,private,protected,public.如果不加修饰符,表示包级可见。

可以对类或类的成员方法加上访问修饰符。

成员可见表示其他类可以用这个类的实例访问该成员。
类可见表示其他类可用这个类来创建对象。
protected用于修饰成员,表示在继承体系修饰成员对于子类可见,但这个访问修饰符对于类没有意义。

设计良好的模块会隐藏所有实现的细节,把它的api和实现清晰地分开。模块之间只通过api进行通讯,一个模块不需要知道其他模块的实现细节,这个概念就是封装。访问权限尽可能 使每个类或者成员不被外界访问。

如果子类的方法覆盖了父类的方法,那么子类中该方法的访问级别不允许低于父类的访问级别,这是为了确保可以使用父类实例的地方都可以使用子类实例,满足里氏替换原则。

字段决不能是公有的,这样做的话就失去了对这个字段修改行为的控制,客户端可以随意进行修改,可以提供公有的get和set方法。
  • 抽象类和接口

    抽象类和抽象方法都使用abstract进行声明,抽象类一般会包含抽象方法,抽象方法一定在抽象类中。
    抽象类和普通类的最大区别,抽象类不能被实例化,需要继承抽象类才能实例化其子类。
    
  • 接口

    接口是抽象类的延伸,在java8之前,他不能有任何方法的实现。
    java8之后,接口也可以有默认的方法实现,不支持默认方法的接口维护成本太高了,在java8之前,如果一个接口想添加新的方法,那么要修改所有实现了该接口的类。
    
    接口可以包含字段,并且这些字段隐氏都是是static和final的。
    
    接口的方法默认都是public的,并且不允许为private和protected。
    
  • 比较

    从设计层面看,抽象类提供了一种IS-A关系,那么就必须满足里氏替换原则,子类必须能够替换掉所有的父类对象。

    一个类可以实现多个接口,但是不能继承多个抽象类。

    接口的字段只能是static和final类型的,而抽象类的字段没有这种限制。

    接口的方法只能是public,而抽象类的方法可以是多种访问权限。

  • 使用选择

    使用抽象类:

    * 需要在几个相关的类中共享代码。
    * 需要能控制继承来的方法和域的访问权限,而不是都为public
    * 需要继承非静态和非常量字段
    

    使用接口:

    * 需要让不相关的类都实现一个方法,例如不相关的类都实现Compareable接口中的CompareTo()方法
    * 需要使用多重继承。
    

    在很多情况下,接口优先于抽象类,因为接口没有抽象类严格的类层次结构要求,可以灵活地为一个类添加行为。 并且从java8开始,接口也可以有默认的方法实现,使得修改接口的成本变的很低。

  • super

    访问父类的构造函数:可以使用super()函数访问父类的构造函数,从而完成一些初始化化工作。
    访问父类的成员:如果子类覆盖了弗雷的某个方法的实现,可以通过使用super关键字来引用父类的方法实现。
    
  • 重写和重载

    重写(覆盖)(override)存在于继承体系中,指子类实现了一个与父类方法声明上完全相同的一个方法;
    重载(overload) 在同一个类中,一个方法与已经存在的方法方法名称相同,但是参数类型,个数,顺序至少有一个不相同。注意:返回值不同,其他都相同不是重载。
    

5 . string

  • String StringBuffer StirngBuild

    5.1 是否可变

            String不可变
            StringBuffer和StringBuilder可变
    

    5.2是否线程安全

            String不可变,因此是线程安全的
            StringBuilder不是线程安全的。
            StringBuffer是线程安全的,内部使用synchronized锁来同步
    
  • String不可变的原因

            可以缓存hash值:因为Stirng的hash值经常被使用,例如string经常用作hashMap的key值。不可变得特行使得hash值也不可变,因此只需计算一次。
            Stirngpool的需要:如果一个String对象已经被创建,那么就会从String Pool中取得引用。只有String是不可变得,才可能使用String Pool。
            安全性:String 经常作为参数,String的不可变性可以保证参数不可变。例如在作为网络连接的参数的情况下,如果String是可变的,那么在网络连接过程中,String的值被改变了,改变String对象的那一方以为连接的是其他主机,而实际情况却不是。
            线程安全:String不可变性天生具备线程安全,可以在多个线程安全使用。
    
  • Stirng.intern()

            使用String.intern()可以保证相同内容的字符串实例引用相同的内存对象。
    

6 基本类型和与运算

类型 字节 位数
int432
boolean1/81
byte18
char216
short216
float432
long864
double864

java会将一些基本类型的值放在缓冲池中,包括下面这些:

  • boolean vaues true and false
  • all bytes values
  • short values between -128 and 127
  • int values between -128 and 127
  • char in the range \u0000 to \u007f

switch

在java7 以后,switch的条件判断语句中可以使用string对象。

switch不支持long,因为switch的设计初衷是为那些需要少数的几个值进行等值判断,如果过于复杂,还是用if比较方便。
switch支持的类型’char, byte, short, int, Character, Byte, Short, Integer, String, or an enum’ 。

七 反射

每一个类都有一个class对象,包含了与类有关的信息。当编译一个心类的时候,会产生一个同名的class对象,改文件内容保存着class对象。

类加载相当于class对象的加载,类在第一次使用时才动态加载到JVM中,可以使用Class.forName()这种方式来控制类的加载,该方法会返回一个class对象。

反射可以提供类运行的信息,并且这个类可以在运行时才加载进来,甚至在编译期该类的.class文件不存在,也可以加载进来。

class和java.lang.reflect一起对反射提供了支持,java.lang.reflect类库主要包含了一下三个类。
* Field 可以使用get()和set()方法读取Field对象关联的字段。
* Method 可以使用invoke()方法调用与method对象关联的方法
* Constructor 可以用Constructor创建新的对象

ide使用反射机制获取类的信息,在使用一个类的对象时,能够把类的字段,方法和构造函数等信息列出来供用户选择。

程序中一般的对象类型都是在编译器就确定下来的,而java反射机制可以动态地创建对象并调用其属性,这样的对象的类型是在编译器未知的。我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

反射的核心就是JVM在运行时才能动态加载类或调用方法/访问属性,他不需要事先知道运行对象是谁。

java反射框主要提供一下功能:

* 在运行时判断任意一个对象所属的类
* 在运行时构造任意一个类的对象
* 在运行时判断任意一个类所具有的成员变量和方法。(通过反射甚至可以调用private方法)
* 在运行时调用任意一个对象的方法。

反射的主要用途:

    比如我们使用IDE(eclipse,IDEA),当我们输入一个对象或类想调用它的方法或属性时,一按点号,编译器就会自动罗列出它的属性或方法,这里就会用到反射。

反射的最重要用途就是开发各种通用的框架。

    许多框架都是配置化的,为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射--运行时动态加载需要加载的对象。

反射的基本应用:

获得class对象:方法有三种

  1. 使用class类的forName静态方法

    在jdbc开发中,常用此方法加载驱动
    Class.forName(driver);
    
  2. 直接获取某一个对象的class

    Class<?> kclass = int.class;
    Class<?> classInt = Integet.Type;
    
  3. 调用某个对象的getClass()方法,比如

    StringBuilder str = new StringBuilder(“123”);
    Class<?> kclass = str.getClass();
    

判断是否为某个类的实例:

可以使用instanceof关键字来判断是否为某个类的实例,也可以通过反射中Class对象的isInstance()方法来判断是否为某个类的实例。

创建实例
通过反射来生成对象主要有两种方式。

    1.使用Class对象的newInstance()方法来创建Class对象对应类的实例。
    Class<?> c = String.class;
    Object str = c.newInstance();
    2.先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的
    Class<?> c = String.class;
    Constructor constructor = c.getConstructor(String.class);
    Object obj = constuctor.newInstance(“23333”);
  1. 获取方法

    获取某个Class对象的方法的集合,主要有以下几个方法。

    getDeclaredMethods()方法返回类或接口声明的所有方法。包括,公共,保护,默认,私有方法,但不包括继承方法。

    public Method[] getDeclaredMethods() throws SecurityException
    

    getMethods()方法返回某个类的所有公有方法(public),包括其继承的公有方法

    public Method[] getMethods() throws SecurityException
    

    getMethod()方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

    public Method getMethod(String name, Class<?>... parameterTypes)
    

下面例子理解这三个方法

    package org.ScZyhSoft.common;
    import java.lang.reflect.InvocationTargetException;
    import jva.lang.reflect.Method; 
    public class test1 {
    public static void test() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> c = methodClass.class;
        Object object = c.newInstance();
        Method[] methods = c.getMethods();
        Method[] declaredMethods = c.getDeclaredMethods();
        //获取methodClass类的add方法
        Method method = c.getMethod("add", int.class, int.class);
        //getMethods()方法获取的所有方法
        System.out.println("getMethods获取的方法:");
        for(Method m:methods)
            System.out.println(m);
        //getDeclaredMethods()方法获取的所有方法
        System.out.println("getDeclaredMethods获取的方法:");
        for(Method m:declaredMethods)
            System.out.println(m);
    }
}
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
    return a+b;
}
public int sub(int a,int b) {
    return a+b;
}
}   

5.获取构造器信息

获取构造器的用法和上述获取方法的用法类似,主要是通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例。

public T newInstance(Object ... initargs)

此方法可以根据传入的参数调用对应的Constructor创建对象实例。

6.获取类的成员变量(字段)信息

主要是这几个方法 。

    getFiled() 访问公有的成员变量
    getDeclaredField() 所有已声明的成员变量,但不能得到其父类的成员变量。
    getFileds()和getDeclaredFields()

7.调用方法

当我们从类中获取了一个方法后,就可以用invoke()方法来调用这个方法,invoke方法的原型为:

    public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
       InvocationTargetException

下面是一个实例:

        public class test1 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
    Class<?> klass = methodClass.class;
    //创建methodClass的实例
    Object obj = klass.newInstance();
    //获取methodClass类的add方法
    Method method = klass.getMethod("add",int.class,int.class);
    //调用method对应的方法 => add(1,4)
    Object result = method.invoke(obj,1,4);
    System.out.println(result);
}
    }
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
    return a+b;
}
public int sub(int a,int b) {
    return a+b;
}
}
  1. 利用反射创建数组

数组在java里是比较特殊的一种类型,他可以赋值个一个Object。利用反射创建数组的例子。

    public static void testArray() throws ClassNotFoundException {
    Class<?> cls = Class.forName("java.lang.String");
    Object array = Array.newInstance(cls,25);
    //往数组里添加内容
    Array.set(array,0,"hello");
    Array.set(array,1,"Java");
    Array.set(array,2,"fuck");
    Array.set(array,3,"Scala");
    Array.set(array,4,"Clojure");
    //获取某一项的内容
    System.out.println(Array.get(array,3));
}
  1. 反射的一些注意事项

    由于反射会额外消耗一定的系统资源,因此如果不需要动态创建一个对象,那么就不需要用反射。另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

八 异常

Throwable可以用来表示任何可以作为异常抛出的类,分为两种:Error和Exception。其中Error用来表示JVM无法处理的错误,Exception分为两种:

* 非运行时异常:需要try 。catch语句捕获并进行处理,并且可以从异常中恢复。
* 运行时异常:程序运行时错误,例如除0会引发异常,此时程序崩溃并且无法恢复。

java提供了一个健壮的,面向对象的方法来处理异常,成为java异常处理。

8.1什么是java异常?

    异常是发生在程序执行过程中阻碍程序正常执行的错误事件。java异常处理框架只能处理运行运行时错误,编译错误不在其考虑范围之内。

8.2 java异常处理的关键字?

    throw :有时我们需要显示地创建并抛出异常对象来终止程序的正常执行。throw关键字用来抛出并处理运行时异常。
    throws:我们抛出异常并不处理,需要在方法签名中使用关键字throws来告知调用程序此方法可能会抛出的异常。调用方法可能会处理这些异常,或者同样用throws来将异常传递给上一级调用的方法。throws后面可以跟多个潜在的异常,甚至在main方法中也可以抛出异常。
    try-catch : 我们在代码中使用try-catch块处理异常。一个try块后面可以优多个catch字句,每个catch必须接收一个代表异常类型的参数。
    finally:finally是可选的, 并且只能配合try-catch使用。有些时候虽然异常终止了程序的运行,但是还有一些打开的资源没有被关闭。因此我们使用finally进行关闭,不管异常有没有出现,finall块总会被执行

8.3 描述一下异常的层级

    java异常是层级的,并通过继承来区分不同种类的异常。

    Throwable是所有异常的父类,他有两个子对象Error和Exception。Exception又被继承为运行时异常和编译时异常。Error表示编译和运行时系统错误,通常不能预期和恢复,比如硬件故障,jvm崩溃,内存不足等。

    被检查时异常(checked Exception) 在程序中能预期,并要尝试修复。比如FileNotFoundException,我们必须捕获此类异常,并为用户提供有用信息和日志进行调试。Exceptin是所有被检查时异常的父类。
    运行时异常(Runtime Exception),源于糟糕的编程,比如我们检索数组元素之前必须确认数组的长度,否则就会抛出ArrayIndexOutOfBoundEception运行时异常。RuntimeException是所有运行时异常的父类。

8.4 java异常有哪些重要方法?

Exception和他的多有子类没有提供任何特殊方法使用,他们的所有方法都是来自其基类Throwable。

* String getMessage() 方法返回Throwable的String型消息,当异常通过构造器创建后可用。
* String getLocalizedMessage() 
* synchronized Throwable getCause() 返回异常产生的原因,如果不知道原因的话返回null。
* String toString() 返回Stirng格式的Throwable信息,此信息包含Throwable的名字和本地化信息。
* void printStackTrace() 打印栈轨迹信息到标准错误流。

8.5 java 7 arm特征和多个catch块的使用

如果一个try块中有多个异常需要捕获,catch块中的代码会变的非常丑陋的同时还要多余的代码来记录异常。java7的一个新特性:一个catch语句中可以捕获多个异常。

catch(IOException | SQLException | Exception ex){
 logger.error(ex);
 throw new MyException(ex.getMessage());
}

在大多数情况下,当忘记关闭资源或者资源耗尽出现运行时异常,我们只能用finally字句来关闭资源,这些异常很难调试,我们需要深入到资源使用的每一步来确定是否已关闭。因此 java7使用try-with-resources进行了改进,在try字句中能创建一个资源对象,当程序的执行完try-catch之后,运行环境自动关闭资源。下面是这方面改进的代码

    try (MyResource mr = new MyResource()) {
        System.out.println("MyResource created in try-with-resources");
    } catch (Exception e) {
        e.printStackTrace();
    }

九 泛型

9.1 java中泛型是什么?使用泛型的好处?

泛型提供了编译期的类型安全,确保你能把正确类型的对象放入集合中,避免了运行时出现ClassCastException。

9.2 java的泛型是如何工作的?什么是类型擦除?

泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型的相关信息,所以在运行时不存在任何类型相关的信息。例如List<Stirng>在运行时仅用一个List来表示。这样做的目的,是确保能和java5之前的版本开发二进制类库进行兼容。你无法在运行时访问到参数类型,因为编译器已经把泛型转化成了原始类型。

9.3 什么是泛型中的限定通配符和非限定通配符》

限定通配符对类型进行了限制。有两种限定通配符,一种是<? extends T>他确保类型必须是T的子类来设定类型的上界,另一种是<? super T> 它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来初始化,哦负责会导致编译错误,另一方面<?> 表示了非限定通配符,因为<?>可以用任意的类型来替代。

9.4 List

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值