• 面试题目


     
    java:
     
     
    关于string和stringbuffer:

    String 长度大小不可变

    StringBuffer 和 StringBuilder 长度可变

    StringBuffer 线程安全 StringBuilder 线程不安全

    StringBuilder 速度快
     
     
    • 基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。
    • 不要使用String类的"+"来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则。
    • 为了获得更好的性能,在构造 StringBuffer 或 StringBuilder 时应尽可能指定它们的容量。当然,如果你操作的字符串长度(length)不超过 16 个字符就不用了,当不指定容量(capacity)时默认构造一个容量为16的对象。不指定容量会显著降低性能。
    • 相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer。
    • StringBuilder一般使用在方法内部来完成类似"+"功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer主要用在全局变量中。
     
     
     
     
    关于关系
     
     
     
     

    Collection

    ├List
    │├LinkedList
    │├ArrayList
    │└Vector
    │ └Stack
    └Set
    Map
    ├Hashtable
    ├HashMap
    └WeakHashMap
     
     
    关于重载和重写:
     
    重载是在一个类中定义多个方法名相同但参数列表不同的方法。 重写是在子类中定义和父类完全相同的方法
    区别点重载方法重写方法
    参数列表 必须修改 一定不能修改
    返回类型 可以修改 一定不能修改
    异常 可以修改 可以减少或删除,一定不能抛出新的或者更广的异常
    访问 可以修改 一定不能做更严格的限制(可以降低限制)
     
     
     
    关于hashmap hashtable:
     

    HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。

    1. HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
    2. HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
    3. 另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
    4. 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
    5. HashMap不能保证随着时间的推移Map中的元素次序是不变的。
     
     
     

    hashcode和equals的约定关系如下:

    1、如果两个对象相等,那么他们一定有相同的哈希值(hash code)。

    2、如果两个对象的哈希值相等,那么这两个对象有可能相等也有可能不相等。(需要再通过equals来判断)

    关于类型转换:
     
    byte+byte=int,低级向高级是隐式类型转换,高级向低级必须强制类型转换,byte<char<short<int<long<float<double
    数值型变量在默认情况下为Int型,byte和short型在计算时会自动转换为int型计算,结果也是int 型。
     
    b6=b4+b5;b4、b5为final类型,不会自动提升,所以和的类型视左边变量类型而定,即b6可以是任意数值类型;
     
    关于i = i++ 值不变:
     
    如果你理解JVM的内存模型,就不难理解为什么答案返回的是0,而不是1。
    我们单独看问题中的这两句代码。
    1
    int i = 0; i = i++;
    Java虚拟机栈(JVM Stack)描述的是Java方法执行的内存模型,而JVM内存模型是基于“栈帧”的,每个栈帧中都有 局部变量表 和 操作数栈 (还有动态链接、return address等),那么JVM是如何执行这个语句的呢?通过javap大致可以将上面的两行代码翻译成如下的JVM指令执行代码。
    0: iconst_0
    1: istore_1
    2: iload_1
    3: iinc          1, 1
    6: istore_1
    7: iload_1
     
    接下来分析一下JVM是如何执行的:
    第0:将int类型的0入栈,就是放到操作数栈的栈顶
    第1:将操作数栈栈顶的值0弹出,保存到局部变量表 index (索引)值为1的位置。(局部变量表也是从0开始的,0位置一般保存当前实例的this引用,当然静态方法例外,因为静态方法是类方法而不是实例方法)
    第2:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶的值也是0)
    第3:iinc是对int类型的值进行自增操作,后面第一个数值1表示,局部变量表的index值,说明要对此值执行iinc操作,第二个数值1表示要增加的数值。(这时局部变量表index为1的值因为执行了自增操作变为1了,但是操作数栈中栈顶的值仍然是0)
    第6:将操作数栈顶的值弹出(值0),放到局部变量表index为1的位置(旧值:1,新值:0),覆盖了上一步局部变量表的计算结果。
    第7:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶的值也是0)
     
    总结:从执行顺序可以看到,这里第1和第6执行了2次将0赋值给变量i的操作(=号赋值),i++操作是在这两次操作之间执行的,自增操作是对局部变量表中的值进行自增,而栈顶的值没有发生变化,这里需要注意的是保存这个初始值的地方是操作数栈而不是局部变量表,最后再将栈顶的值覆盖到局部变量表i所在的索引位置中去。
     
    有兴趣的同学可以去了解一下JVM的栈帧(Stack Frame)
     
    关于第二个陷阱(为什么 fermin方法没有影响到i的值 )的解答看下面。
    1
    inc.fermin(i);
    1. java方法之间的参数传递是 值传递 而不是 引用传递
    2. 每个方法都会有一个栈帧,栈帧是方法运行时的数据结构。这就是说每个方法都有自己独享的局部变量表。(更严谨的说法其实是每个线程在执行每个方法时都有自己的栈帧,或者叫当前栈帧 current stack frame)
    3. 被调用方法fermin()的形式参数int i 实际上是调用方法main()的实际参数 i 的一个副本。
    4. 方法之间的参数传递是通过局部变量表实现的,main()方法调用fermin()方法时,传递了2个参数:
    第0个隐式参数是当前实例(Inc inc = new Inc(); 就是inc引用的副本,引用/reference 是指向对象的一个地址,32位系统这个地址占用4个字节,也就是用一个Slot来保存对象reference,这里传递的实际上是reference的一个副本而不是 reference本身 );
    第1个显示参数是 i 的一个副本。所以 fermin()方法对 i 执行的操作只限定在其方法独享或可见的局部变量表这个范围内,main()方法中局部变量表中的i不受它的影响;
     
    如果main()方法和fermin()方法共享局部变量表的话,那答案的结果就会有所不同。 其实你自己思考一下,就会发现, JVM虚拟机团队这么设计是有道理的。
     
     
     
     
    关于一些关键字:
     
     
     
    1abstract类不能与final,static使用。final修饰方法,子类可以调用,但不能覆盖。
    2最好不要有private因为私有和抽象放在一起,子类如果想重写父类的私有方法根本继承不过来,也就无法重写
    3抽象类中可以有非抽象方法
    4抽象类中可以都是非抽象的,但是抽象方法一定要在类和接口中
     
    作用域         当前类          同一package           子孙类                其他package 
    public              √                    √                           √                             √ 
    protected         √                    √                            √                            × 
    friendly            √                    √                            ×                            × 
    private             √                     ×                            ×                             ×
    没有时默认为friendly,如构造函数等~
    default 权限限于同一个包中,即包权限=default权限
     
     
    linux:
     
     
     
    关于命令:
     
    route add -net [目的子网] gw [网关地址] netmask [子网掩码] metric [路由跳数]
    这里添加的静态路由信息应该是从网关192.168.1.1到达目的子网172.16.1.0所需路由跳数为1跳。
     
    关于进程通讯:
     
    方式:

    UNIX中有如下的通信方式:

    1) 文件和记录锁定。

    为避免两个进程间同时要求访问同一共享资源而引起访问和操作的混乱,在进程对

    共享资源进行访问前必须对其进行锁定,该进程访问完后再释放。这是UNIX为共享

    资源提供的互斥性保障。

      2 )管道。

    管道一般用于两个不同进程之间的通信。当一个进程创建一个管道,并调用fork创

    建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样 提供了

    两个进程之间数据流动的一种方式。

      3 ) FIFO 。

    FIFO是一种先进先出的队列。它类似于一个管道,只允许数据的单向流动。每个

    FIFO都有一个名字,允许不相关的进程访问同一个FIFO。因此也成为命名管。

     4)消息队列。

    UNIX下不同进程之间可实现共享资源的一种机制;UNIX允许不同进程将格式化的数

    据流以消息形式发送给任意

    进程。对消息队列具有操作权限的进程都可以使用msget完成对消息队列的操作控制

    。通过使用消息类型,进程可以按任何顺序读消息,或为消息安排优先级顺序。

      5 )信号灯。

    作为进程间通讯的一种方法,它不是用于交换大批数据,而用于多进程之间的同步

    (协调对共享存储段的存取)。

      6 )共享内存。

    通过信号灯实现存储共享(类似“红灯停、绿灯行”)

     
    关于文件权限:
     
    第一位表示是文件或者目录(d表示目录directory;l表示连接link。),2~4是用户权限, 5~7是组权限 ,8~10是其他用户权限
     
     
    • 为了更加安全的存储文件,Linux为不同的文件赋予了不同的权限,每个文件都拥有下面三种权限:

      ·        所有者权限:文件所有者能够进行的操作

      ·        组权限:文件所属用户组能够进行的操作

      ·        外部权限(其他权限):其他用户可以进行的操作。

      查看文件权限

      ls -l  命令可以查看与文件权限相关的信息:

      $ls -l /home/amrood
      -rwxr-xr--  1 amrood   users 1024  Nov 2 00:10  myfile
      drwxr-xr--- 1 amrood   users 1024  Nov 2 00:10  mydir

      第一列就包含了文件或目录的权限。 

      第一列的字符可以分为三组,每一组有三个,每个字符都代表不同的权限,分别为读取(r)、写入(w)和执行(x):

      ·        第一组字符(2-4)表示文件所有者的权限,-rwxr-xr-- 表示所有者拥有读取(r)、写入(w)和执行(x)的权限。

      ·        第二组字符(5-7)表示文件所属用户组的权限,-rwxr-xr-- 表示该组拥有读取(r)和执行(x)的权限,但没有写入权限。

      ·        第三组字符(8-10)表示所有其他用户的权限,rwxr-xr-- 表示其他用户只能读取(r)文件。

      文件访问模式

      文件权限是Linux系统的第一道安全防线,基本的权限有读取(r)、写入(w)和执行(x):

      ·        读取:用户能够读取文件信息,查看文件内容。

      ·        写入:用户可以编辑文件,可以向文件写入内容,也可以删除文件内容。

      ·        执行:用户可以将文件作为程序来运行。

      目录访问模式

      目录的访问模式和文件类似,但是稍有不同:

      ·        读取:用户可以查看目录中的文件

      ·        写入:用户可以在当前目录中删除文件或创建文件

      ·        执行:执行权限赋予用户遍历目录的权利,例如执行 cd 和 ls 命令。

      改变权限

      chmod   (change mode) 命令来改变文件或目录的访问权限,权限可以使用符号或数字来表示。

      使用符号表示权限

      可以增加(+)和删除(-)权限,也可以指定特定权限。

      符号

      说明

      +

      为文件或目录增加权限

      -

      删除文件或目录的权限

      =

      设置指定的权限


      下面的例子将会修改 testfile 文件的权限:

      $ls -l testfile
      -rwxrwxr--  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod o+wx testfile
      $ls -l testfile
      -rwxrwxrwx  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod u-x testfile
      $ls -l testfile
      -rw-rwxrwx  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod g=rx testfile
      $ls -l testfile
      -rw-r-xrwx  1 amrood   users 1024  Nov 2 00:10  testfile

      也可以同时使用多个符号:

      $chmod o+wx,u-x,g=rx testfile
      $ls -l testfile
      -rw-r-xrwx  1 amrood   users 1024  Nov 2 00:10  testfile

      使用数字表示权限

      除了符号,也可以使用八进制数字来指定具体权限,如下表所示:

      数字

      说明

      权限

                0

      没有任何权限

      ---

      1

      执行权限

      --x

      2

      写入权限

      -w-

      3

      执行权限和写入权限:1 (执行) + 2 (写入) = 3

      -wx

      4

      读取权限

      r--

      5

      读取和执行权限:4 (读取) + 1 (执行) = 5

      r-x

      6

      读取和写入权限:4 (读取) + 2 (写入) = 6

      rw-

      7

      所有权限: 4 (读取) + 2 (写入) + 1 (执行) = 7

      rwx


      下面的例子,首先使用   ls -1  命令查看 testfile 文件的权限,然后使用  chmod  命令更改权限:

      $ls -l testfile
      -rwxrwxr--  1 amrood   users 1024  Nov 2 00:10  testfile
      $ chmod 755 testfile
      $ls -l testfile
      -rwxr-xr-x  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod 743 testfile
      $ls -l testfile
      -rwxr---wx  1 amrood   users 1024  Nov 2 00:10  testfile
      $chmod 043 testfile
      $ls -l testfile
      ----r---wx  1 amrood   users 1024  Nov 2 00:10  testfile

      更改所有者和用户组

      在Linux中,每添加一个新用户,就会为它分配一个用户ID和群组ID,上面提到的文件权限也是基于用户和群组来分配的。 

      有两个命令可以改变文件的所有者或群组:

      ·        chown :chown 命令是"change owner"的缩写,用来改变文件的所有者。

      ·        chgrp :chgrp 命令是"change group"的缩写,用来改变文件所在的群组。


      chown   命令用来更改文件所有者,其语法如下:

      $ chown user filelist

      user 可以是用户名或用户ID,例如

      $ chown amrood testfile
      $

      将 testfile 文件的所有者改为 amrood。 

      注意:超级用户 root 可以不受限制的更改文件的所有者和用户组,但是普通用户只能更改所有者是自己的文件或目录。 

      chgrp   命令用来改变文件所属群组,其语法为:

      $ chgrp group filelist

      group 可以是群组名或群组ID,例如

      $ chgrp special testfile
      $

      将文件 testfile 的群组改为 special。

       
       
       
       
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    Windows环境下阿里云添加SSH Key及Git配置Key
    Shiro自定义注解扩展@SalmonRequiresPermission
    windows下安装redis
    模型-视图-控制器的C++解释
    CentOS 7 搭建 GitLab
    博客园主题分享——绿色
    2019年的第一篇博客
    Qt——线程与定时器
    Qt——线程类QThread
    QML——添加自定义模块
  • 原文地址:https://www.cnblogs.com/shizhenqiang/p/7656446.html
Copyright © 2020-2023  润新知