美文网首页安卓面试晚期代码癌患者JAVA
面试必备--Java基础知识复习

面试必备--Java基础知识复习

作者: bu_想 | 来源:发表于2017-03-13 20:32 被阅读3485次

    static的作用

    static表示静态修饰符,使用static修饰的变量,在Java中分配内存后一直存在,直到程序退出才释放空间。用static修饰的变量可以直接使用类名加“.”的方式访问。

    final的作用

    final表示不可改变的。如果修饰类,表示该类是一个最终类,不可被继承,默认其中的方法都为final方法。如果修饰方法,不能被子类覆盖,但是能被子类继承(父类中的private方法也是不能被子类覆盖的,默认也是final)。如果修饰成员变量,表示该变量是一个常量,只能被赋值一次,赋值之后不可以被改变。

    overload和override的区别

    重载(overload),表示同一个类中可以有多个方法名相同的方法,但是这些方法的参数列表各不相同(参数个数、类型或者顺序)。
    重写(override),表示子类对父类中的某个方法重新编写,相同的内容包括方法名、参数和返回类型。子类的方法访问修饰符范围要大于等于父类中的范围,子类只能比父类抛出更少的异常。声明为final的方法不能被重写。声明为static的方法不能被重写,但是能被再次声明。子类和父类在同一包下,子类能重写除了private和final的所有方法。子类和父类不在同一包下,子类只能重写父类声明为public和protected的方法。

    内部类

    每个内部类都能独立的继承一个接口,与外围类无关。
    成员内部类,作为外部类的成员,可以使用外部类的所有成员和方法,但是外部类要先拥有成员内部类的实例对象,才可以访问内部类。成员内部类不能有任何static的变量或方法。只有先创建外部类,才能在创建成员内部类。(new 外部类实例;外部类名.内部类名 内部类对象名 = 外部类实例.new 内部类类名)。
    局部内部类,是定义在一个方法或者一个作用域里面的类,它的访问权限仅限于该方法或者该作用域内。
    匿名内部类,没有访问修饰符;new 匿名内部类;这里举个简单例子。

    bt.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                }
            });
    

    再看一个例子

    public class Test {
        public static void main(String[] args)  {
             
        }
         
        public void test(final int b) {
            final int a = 10;
            new Thread(){
                public void run() {
                    System.out.println(a);
                    System.out.println(b);
                };
            }.start();
        }
    }
    

    这里test方法的参数为final修饰,在其中还定义了一个final的变量,然后在匿名内部类中进行使用。在run方法中,对于a,java编译器能确定其值,所以在编译的时候会直接在匿名类的常量池中添加一个值相等的变量;对于b,参数的值无法在编译的时候确定,这时会将test方法中的形参a以参数的形式传进来对匿名内部类中的拷贝进行初始化赋值。这里就有一个问题,内部类中的变量和test中的局部变量不是一个对象,所以java直接限制为final变量,不允许改变,这样数据不一致的问题就得到了解决。
    静态内部类,使用static修饰的内部类。内部类不依赖外部类,并且不能使用外部类非static的成员变量或方法,创建静态内部类对象,外部类名.内部类名 内部类对象名 = new 外部类名.内部类类名()。

    Java 二维数组

    定义,type arrayName[][]或者type[][] arrayName。
    静态初始化,int array[][] = {{1,2},{1,2,3},{1,2,3,4}};
    在Java中,把二维数组看作是数组的数组,数组的空间是不连续的,所以不要求二维数组每一维大小相等。
    动态初始化,可以直接给数组的每一维赋值同样的大小,也可以先确定数组最高维的大小,然后给每一维具体分配。int array[][] = new int[2][3];int array[][] = new int[2][],array[0] = new int[5],array[1]=new int[10]。

    接口和抽象类

    抽象类
    可以含有具体的方法;
    子类使用extends关键字来继承抽象类,如果子类不是抽象类,它需要实现父类中所有的抽象方法,或者继续声明为抽象类;
    抽象类中也可以不含抽象方法;
    抽象类中可以有成员变量;
    抽象类可以有构造函数,只是不能直接用来创建抽象类的实例,在继承了抽象类的子类中可以通过super调用抽象类中的构造函数;
    抽象类可以继承一个类实现多个接口。
    接口
    接口中可以且只能有 public static final修饰的常量。
    子类需要使用implements实现接口,需要实现接口中声明的所有方法;
    接口没有构造函数;
    接口默认修饰符是public,不能改为其他修饰符。

    反射机制

    Java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法,对于任意一个对象,都能调用他的任意方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

    通过反射获得类的包名和类名等类的相关信息。

    Test test = new Test();
    //获得包名
    test.getClass().getPackage().getName();
    //获得类名
    test. getName();
    

    通过Class类获得Test类的实例对象

     //定义一个类型未知的Class类,
    Class<?> class = null;
    //方法1
    class = Class.forName("com.king.test");
    //方法2
    class = Test.class;
    

    通过反射,用Class创建类对象

    Class<?> class = null;
    class = Class.forName("com.king.test");
    Test test = (Test)class.newInstance();
    //然后就可以调用test对象的方法了。
    

    java面向对象的三个特征和含义

    继承:继承是从已有的类得到继承信息创建新类的过程。提供继承信息的类被称为父类(基类、超类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的可延续性,同时继承也是封装程序中可变因素的重要手段。
    封装:在类中编写的方法是对实现细节的封装,编写一个类就是对数据和数据操作的封装。封装就是隐藏一切可隐藏的东西,只向外界提供最简单的接口。
    多态:多态是指允许不同子类型的对象堆同一消息做出不同的响应。
    编译时多态:是指根据参数列表不同来区分不同的函数,编译之后就会变成两个函数,主要指方法的重载。
    运行时多态:(动态绑定),指在程序运行期间判断所引用对象的实际类型,根据实际类型判断并调用相应的方法和属性。
    要实现多态需要做两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

    Java线程和进程

    线程存在于进程中,每个进程都至少一个线程。线程共享进程的资源,包括内存和打开的文件。进程和线程是并发编程的两个基本的执行单元。在 Java 中,并发编程主要涉及线程。
    java实现多线程的两种方式,1.继承Thread类,2.实现Runnable接口。

    进程的基本状态及其转换
    一个线程可以处于以下四种状态之一:
    1.新建。当线程被创建时,它只会短暂的处于这种状态。此时它已经分配了必须的系统资源,并执行了初始化。此刻线程已经有资格获取CPU时间了,之后调度器把这个线程转变为可运行状态或者阻塞态。
    2.就绪。在这种状态下,只要调度器把时间片分配给线程,线程就可以运行。也就是说,在任意时刻,线程可以运行或者不运行。只要调度器能分配时间片给线程,他就可以运行,这不同于死亡和阻塞状态。
    3.阻塞。线程能够运行,但是有个条件阻止它的运行。当线程处于阻塞状态时,调度器会忽略线程,不会分配给线程CPU时间。直到线程重新进入就绪态,它才有可能执行操作。
    4.死亡。处于死亡或者终止状态的线程不再是可调度的。并且再也不会得到CPU时间。任务死亡的通常方式是从run()方法返回,但是任务线程还可以被中断。
    Java中使用synchronized关键字来实现同步。
    run()和start()
    系统通过调用start()方法来启动一个线程,此时该线程处于就绪态。直接调用run()方法,这会被当成一个普通的函数调用,程序中仍然只有主线程一个线程。
    wait()和notify()
    在synchronized代码被执行期间,线程可以调用对象的wait()方法,释放对象锁,进入等待状态,直到其他线程调用此对象的 notify()方法或 notifyAll()方法。notify()唤醒等待队列的第一个线程,并运行它去获取锁。notifyAll(),唤醒等待队列的全部线程,让他们去竞争锁。
    Java 5加入了Lock接口以及他的一个实现类ReentrantLock(重入锁)。lock()方法。以阻塞的方式获取锁。如果获得到锁,立即返回;如果别的线程持有锁,则当前线程等待,直到获取锁之后返回。tryLock(),非阻塞形式获取锁,如果获取到返回true,没有获取到,返回false。
    sleep()和wait()
    sleep不会释放锁,wait会释放锁。
    join
    join方法用线程对象调用,如果在一个线程A中调用另一个线程B的join方法,线程A将会等待线程B执行完毕后再执行。
    this和super
    this用来指向当前实例的对象,用来区分成员变量和方法的形参,如果方法的形参和成员变量的名字相同的时候,方法的形参会覆盖成员变量。
    super用来访问父类的方法或成员变量。
    volatile
    使用这个修饰符修饰的变量,程序在读取它的值时直接从内存中获取,一定是最新值。而不是从缓存中获取。

    其他

    值传递和引用传递
    值传递。在方法调用过程中,实参将自己的值传递给形参使用,虽然两者的值完全相等,但是在内存中确实完全不同的位置,对形参的改变不会影响到实参。
    引用传递。在方法调用中,传递的是对象的地址,这是形参和实参其实指向的是同一块存储单元。
    在Java中,8种基本数据类型都是值传递,包装类都是值传递。
    Math中的round、ceil和floor
    round四舍五入,返回结果int。
    ceil向上取整,返回double。
    floor向下取整,返回double。
    Java I/O流
    字节流:InputStream和outputStream
    字符流:Reader和Writer
    Socket
    流套接字,使用TCP协议。提供面向连接的服务。提供可靠连接。Java为TCP连接提供了两个类,Socket和ServerSocket类。一个Socket实例代表了TCP连接的一个客户端,一个ServerSocket代表一个服务端,一般在程序中会有多个客户端,一个服务端。客户端向服务端发送连接请求,服务端的ServerSocket实例监听来自客户端的连接请求,并为每个请求创建新的socket实例并开启新线程。serverSocket调用eccept()方法监听。每个Socket实例会关联一个InputStream和OutputStream。通过将数据写入OutputStream发送数据,通过InputStream接收数据。通信完成记得关闭连接。
    数据报套接字,使用UDP协议。面向非连接的,不可靠连接。服务端和客户端都是使用DatagramSocket的send()和receive()方法接收和发送数据。由于UDP是无连接的,所以服务端不用等待客户端请求连接。UDP服务器为所有通信使用同一套接字。如果数据在传输过程中发生丢失,那么程序会一直阻塞在recevice()处。为避免这个问题,可以设置recevice()的最长阻塞时间,并指定重发数据报的次数。
    堆和栈
    Java中,基本数据类型的变量以及对象的引用变量,内存都分配在栈上。
    而引用类型的变量,内存都分配在堆上或者常量池。
    关于Collection
    List、Queue、Set、Stack继承自Collection接口。
    Set,其中的元素不能重复。线程不同步。有两个实现类:HashSet和TreeSet。TreeSet实现了SortedSet接口,底层的数据结构是二叉树,是有序的。
    List,ArrayList和Vector是基于数组实现的,只在末端添加删除元素快,随机访问快,Vector是线程安全的。LinkedList是基于双向链表的,在指定位置插入数据速度快。
    Collection包结构,与Collections的区别
    Collection是一个接口,他是Set、List等容器的父接口;Collections是一个工具类,提供一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等。
    Map集合
    这个集合是存储键值对的,实现类有:
    HashTable,底层是哈希表数据结构,不可存入null键和null值,线程同步。
    HashMap,底层是哈希表数据结构,可以存入null键和null值,线程不同步,效率较高。
    TreeMap,底层是二叉树数据结构,实现了SortMap接口,线程不同步,可以用于map集合中对键进行排序。
    String类
    String对象是不可变类型,一般返回类型为String的String方法每次返回的都是新的对象。
    String对象的比较方式:
    ==内存比较,直接比较两个引用所指向的内存值,精确简介直接明了。
    equals字符串值比较,比较两个引用所指对象字面值是否相等。
    Object有哪些公用方法
    1.clone方法,实现对象的浅复制,只有实现了Cloneable接口才能调用 该方法。
    2.getClass方法,final方法,获得运行时类型。
    3.toString方法,一般由子类覆盖。
    4.finalize方法,用于释放资源,因为无法确定该方法什么时候被调用,很少有。
    5.equals方法。很重要的一个方法,用于比较,子类一般需要重写。
    6.hashCode方法,该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
    7.wait方法,调用该方法后当前线程进入睡眠状态,直到以下事件发生
    (1).其他线程调用了该对象的notify方法或notifyAll方法。
    (2).其他线程调用了interrupt中断该线程。
    (3)wait(long time)设置中的时间间隔到了。
    此时如果线程被中断就抛出一个InterruptedException异常,或者是处于可以被调度的状态。
    8.notify,唤醒等待该对象的某个线程。
    9.notifyAll,唤醒等待该对象的所有线程。
    Throwable
    Throwable是Java中所有错误和异常的超类。包含两个子类,Error和Exception。RuntimeException是Exception的一个子类,表示可能在Java虚拟机正常运行期间抛出的异常的超类,编译器不会检查Error 和RuntimeException,要通过修改代码来避免这些情况。
    checkException,被检查的异常,Exception类本身,以及Exception的子类中除了RuntimeException之外的其他子类都属于被检查异常,这些异常Java编译器会检查它。此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。

    相关文章

      网友评论

      • KongOL:双击李刚666
      • 萌萌的英子:加油 加油
      • 倾情123:没毛病
      • 瞎晃的攻城狮:还是有点薄,比如final,一般我会问 :为什么用finnal,什么时候用final?
        HashMap为啥不用步,想同步怎么办,有没有高效的同步方式?
        看客们还是要多想几层,现在面都会问深一些的
        bu_想:恩恩,这些也只是基础知识,扩展肯定还是大家根据自己学习的方向去延伸的
      • 米斯特灬:收益很大
      • 吴高亮:厉害,面试看这个就行

      本文标题:面试必备--Java基础知识复习

      本文链接:https://www.haomeiwen.com/subject/yepegttx.html