远景面试,凉凉

  • 远景电话面
Java有没有写过小项目、数据结构排序算法(快速排序、冒泡排序),以及其时间复杂度,最好和最坏的情况,怎么出来的。

  • 远景现场面

Q1:白纸写代码 + 讲思路 + 计算复杂度
给定一个整数,输出其32位的十六进制形式,例如 输入-1,输出ffffffff;输入27,输出1b; String tohex(int num){}
import java.util.Scanner; public class tohex {
    String tohex(int num){
      if(num >=0){  return transe(num);
          }else{ return transe((long) Math.pow(16,8)+num);
        }
    }
    String transe(long num){
        StringBuffer s = new StringBuffer(); long temp = 0;  while (num!=0){
            temp = num%16;
            s.append(sixteen(temp));
            num = (num-temp)/16;
        } return s.reverse().toString();
    }
    String sixteen(long num){ if(num <= 9 && num >= 0) return (num +"");  else  return (char)(num - 10 + 'A') +"";
    } public static  void  main(String[] args){
        tohex t = new tohex();
        Scanner in = new Scanner(System.in);  int n = in.nextInt();
        System.out.println(t.tohex(n));
    }
}


Q2:给定一个整数,让输出其2的幂方的上界,不允许使用上述进制的循环除法,例如输入13,输出16,输入17,输出32;

import java.util.Scanner; public class Upperbound {  public int upper2(int num){  int k = (int) Math.ceil(Math.log(num)/Math.log(2)); return (int) Math.pow(2,k);
    }  public static void main(String[] args){
        Upperbound u = new Upperbound();
        Scanner in = new Scanner(System.in);  int n = in.nextInt();
        System.out.println(u.upper2(n));
    }
}

Q3:讲讲研究生的项目==>本人做的涉及到随机森林,从决策树引发问题
给定邻接矩阵,求最短路径的连接情况==>BFS/最小生成树;

①若从顶点u开始构造最小生成树,则从集合V中取出顶点u放入集合U中,标记顶点v的visited[u]=1; 
②若集合U中顶点ui与集合V-U中的顶点vj之间存在边,则寻找这些边中权值最小的边,但不能构成回路,将顶点vj加入集合U中,将边(ui,vj)加入集合D中,标记visited[vj]=1; 
③重复步骤②,直到U与V相等,即所有顶点都被标记为访问过,此时D中有n-1条边。

import java.util.ArrayList; //插入的边的类 class MGraph { /*图的邻接矩阵表示*/  int vexs; //图中结点数目  char data[]; //存放结点数据  int [][]weight; //存放边  public MGraph(int ve){  vexs=ve; data=new char[ve]; weight=new int[ve][ve];}
} //邻接矩阵类 public class MyAdjGraphic { /*创建图的邻接矩阵*/    public void CreateGraph(MGraph graph,int vexs,char data[],int [][]weight){  int i,j; for(i=0;i<vexs;i++){
                graph.data[i]=data[i];
   for(j= 0;j<vexs;j++){
                    graph.weight[i][j]=weight[i][j];
                }
            }
        }  public void Prim(MGraph graph,int v){ /*graph为图的邻接矩阵表示,v为起始顶点*/    int visited[]=new int[graph.vexs]; // visited[]标记结点是否被访问过 
       for(int i=0;i<graph.vexs;i++){ //初始化visited[] 
       visited[i]=0;
          }
          visited[v]=1;  int h1=-1,h2=-1; //记录边的弧尾和弧头    int minweight=10000;//minweight记录最小权重    for(int k=1;k<graph.vexs;k++){ //vexs个顶点,最小生成树中有vexs-1条边     for(int i=0;i<graph.vexs;i++){ //i顶点表示被访问过的顶点    for(int j=0;j<graph.vexs;j++){ // j顶点表示未被访问过的顶点 
       if(visited[i]==1 && visited[j]==0 && graph.weight[i][j]<minweight){ //寻找已访问的顶点与未访问的定点间的权值最小的边 
       minweight=graph.weight[i][j];
                            h1=i;
                            h2=j;
                        }
                    }
                }
                System.out.println("边<"+graph.data[h1]+","+graph.data[h2]+"> 权值:"+minweight);
                visited[h2]=1; //标记h2被访问过  minweight=10000;
            }
        } public static void main(String args[]){ char []data=new char[]{'A','B','C','D','E'}; int vexs=data.length; int [][]weight=new int[][]{
                    {10000,4,8,5,10000},
                    {4,10000,3,10000,7},
                    {8,3,10000,6,6},
                    {5,10000,6,10000,9},
                    {10000,7,6,9,10000}
            };
            MGraph graph=new MGraph(vexs);
            MyAdjGraphic mt=new MyAdjGraphic();
            mt.CreateGraph(graph,vexs,data,weight);
            mt.Prim(graph, 0);
        }
}


Q4:Python知识  with

文件处理,获取一个文件句柄,从文件中读取数据,然后关闭文件句柄
with open("/tmp/foo.txt") as file:
    data = file.read()

with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。
紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。
class Sample: def __enter__(self): print "In __enter__()" return "Foo" def __exit__(self, type, value, trace): print "In __exit__()" def get_sample(): return Sample()
 
with get_sample() as sample: print "sample:", sample
with真正强大之处是它可以处理异常
with context_manager():  
      1/0      
integer division or modulo by zero 


Q5:Python知识  *arg  **karg
当函数的参数不确定时,可以使用*args 和**kwargs,*args 没有key值,**kwargs有key值
def fun_var_args(farg, *args):      print "arg:", farg      for value in args:          print "another arg:", value    fun_var_args(1, "two", 3) # *args可以当作可容纳多个变量组成的list  result: [python]  arg: 1  another arg: two  another arg: 3
def fun_var_kwargs(farg, **kwargs): 
    print "arg:", farg 
    for key in kwargs: 
        print "another keyword arg: %s: %s" % (key, kwargs[key]) 
 
 
fun_var_kwargs(farg=1, myarg2="two", myarg3=3) # myarg2和myarg3被视为key, 感觉**kwargs可以当作容纳多个key和value的dictionary 
result:
[python] 
arg: 1 
another keyword arg: myarg2: two 
another keyword arg: myarg3: 3 


Q6:Jdk、jre、jvm的关系


JRE和JVM区别:有些人觉得,JVM就可以执行class了,其实不然,JVM执行.class还需要JRE下的lib类库的支持,尤其是rt.jar。
JDK和JRE区别:去bin文件夹下你会发现,JDK有javac.exe而JRE里面没有,众所周知javac指令是用来将java文件编译成class文件的,这是你开发去做的事,用户是不会去做的。JDK还有jar.exe, javadoc.exe等等用于开发的可执行指令文件。这也证实了一个是开发环境,一个是运行环境。
抽象问题具体化理解:
JDK包含了JRE,JRE包含了JVM。

JDKJava Development Kit JDKJava开发工具包,是Sun Microsystems针对Java开发员的产品。

JDK中包含JRE,在JDK的安装目录下有一个名为jre的目录,里面有两个文件夹binlib,在这里可以认为bin里的就是jvmlib中则是jvm工作所需要的类库,而jvm lib和起来就称为jre

JDK是整个JAVA的核心,包括了Java运行环境JREJava Runtime Envirnment)、一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。

SE(J2SE)standard edition,标准版,是我们通常用的一个版本,从JDK 5.0开始,改名为Java SE

EE(J2EE)enterprise edition,企业版,使用这种JDK开发J2EE应用程序,从JDK 5.0开始,改名为Java EE

ME(J2ME)micro edition,主要用于移动设备、嵌入式设备上的java应用程序,从JDK 5.0开始,改名为Java ME

金字塔结构 JDK=JRE+JVM+其它 运行Java程序一般都要求用户的电脑安装JRE环境(Java Runtime Environment);没有jrejava程序无法运行;而没有java程序,jre就没有用武之地。

 

Java Runtime EnvironmentJRE

是运行基于Java语言编写的程序所不可缺少的运行环境。也是通过它,Java的开发者才得以将自己开发的程序发布到用户手中,让用户使用。

JRE中包含了Java virtual machineJVM),runtime class librariesJava application launcher,这些是运行Java程序的必要组件。

与大家熟知的JDK不同,JREJava运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器),只是针对于使用Java程序的用户。

 

JVMjava virtual machine

就是我们常说的java虚拟机,它是整个java实现跨平台的最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行。

也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。

只有JVM还不能成class的执行,因为在解释class的时候JVM需要调用解释所需要的类库lib,而jre包含lib类库。

JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。



Q7:有用过final吗?final的作用?举例那些变量是final修饰?
1、final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量),
当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
使用final方法把方法锁定,以防任何继承类修改它的含义
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

2、例:当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对引用类型的变量而言,它保存的仅仅是一个引用,final只保证这个引用所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。
例:匿名内部类不能访问外部类方法中的局部变量,除非该变量被声明为final类型
    “匿名内部类”主要是指在其外部类的成员方法内定义的同时完成实例化的类,若其访问该成员方法中的局部变量,局部变量必须要被final修饰。原因是编译器实现上的困难:内部类对象的生命周期很有可能会超过局部变量的生命周期。
     局部变量的生命周期:当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。而内部类对象生命周期与其它类对象一样:自创建一个匿名内部类对象,系统为该对象分配内存,直到没有引用变量指向分配给该对象的内存,它才有可能会死亡(被JVM垃圾回收)。所以完全可能出现的一种情况是:成员方法已调用结束,局部变量已死亡,但匿名内部类的对象仍然活着。
    如果匿名内部类的对象访问了同一个方法中的局部变量,就要求只要匿名内部类对象还活着,那么栈中的那些它要所访问的局部变量就不能“死亡”。
    解决方法:匿名内部类对象可以访问同一个方法中被定义为final类型的局部变量。定义为final后,编译器会把匿名内部类对象要访问的所有final类型局部变量,都拷贝一份作为该对象的成员变量。这样,即使栈中局部变量已经死亡,匿名内部类对象照样可以拿到该局部变量的值,因为它自己拷贝了一份,且与原局部变量的值始终保持一致(final类型不可变)



Q8:new 一个对象的过程
类名 变量名;
变量名=new 类名(参数列表);
Vehicle veh1=new vheicle()
这个语句具体的执行过程是:
1、虚拟机先执行Person.class文件
1.右边的“new vheicle"是以vehicle类为模板,在堆空间里创建一个vehicle类对象(也简称vehicle对象)。
    new SubClass()对象时,先检查有没有父类,有父类,类加载器(ClassLoader)先将父类的Class文件读入内存,创建一个java.lang.Class对象,然后加载子类,类加载器将子类的Class文件读入内存,创建一个java.lang.Class对象; 
    先初始化父类的静态属性,再初始化父类的静态代码块; 
    再初始化子类的静态属性,再初始化子类的静态代码;
   在堆内存中分配内存空间,分配内存地址,此时是因为父类的特有属性才在堆内存中为父类对象分配空间。 

2.末尾的()意味着,在对象创建后,立即调用vehicle类的构造函数,对刚生成的对象进行初始化。构造函数肯定是有的,如果没有创建,java会补上一个默认的构造函数。
    初始化父类的特有属性。 
    初始化父类的构造代码块。 
    初始化父类对象相应的构造方法。 
    在堆内存中分配内存空间,分配内存地址,此时是因为子类的特有属性才在堆内存中为子类对象分配空间的。 
    初始化子类的特有属性。 
    初始化子类的构造代码块。 
    初始化子类相应的构造方法。 
    将子类的内存地址赋值给栈中的引用对象
3.左边的'Vehicle veh1'创建了一个vehicle类引用变量
4.“=”操作符使对象引用指向刚创建的Vehicle对象。






Q9:哪些是分配在栈里面的?哪些是分配在堆里面的?堆和栈有什么区别?线程被分配在哪里?

栈存储区——通过操作”堆栈指针”的上下移动来实现堆栈区中对内存的申请和释放.堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存
存放:基本类型的变量数据和对象,数组的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中)
堆区——在于RAM中,存放所有的JAVA对象。编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用堆栈进行存储存储需要更多的时间.
存放所有new出来的对象,而针对堆中对象内存的回收依赖于GC.
静态存储区
存储用static修饰的成员变量或方法.虽然static关键字可以用来标识一个对象是静态的,但JAVA对象本身不会被存放在静态存储空间里,而是存储在堆内存区.
存放static修饰的静态成员(方法或变量)
对于线程:
堆区: 
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令) 
2.jvm只有一个堆区(heap),被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 
栈区: 
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中 
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。 
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。 
方法区: 
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。 
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。


Q10:说说hashmap和hashtable的区别
    1、两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全。Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它Collections.synchronizedXX方法也是类似原理。
    2、HashMap可以使用null作为key,不过建议还是尽量避免这样使用。HashMap以null作为key时,总是存储在table数组的第一个节点上。而Hashtable则不允许null作为key。
    3、HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。
    4、HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75。
    5、HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1。
    6、.判断是否含有某个键 
    在HashMap 中,null 可以作为键,这样的键只有一个;可以有一个或多个键所对 
    应的值为null。当get()方法返回null 值时,既可以表示HashMap 中没有该键,也可 
    以表示该键所对应的值为null。因此,在HashMap 中不能用get()方法来判断HashM 
    ap 中是否存在某个键,而应该用containsKey()方法来判断。Hashtable 的键值都不能 
    为null,所以可以用get()方法来判断是否含有某个键





Q11:hashmap哪些方法是线程不安全的
HashMap底层是一个Entry数组,一旦发生Hash冲突的的时候,HashMap采用拉链法解决碰撞冲突
通过Entry内部的next变量可以知道使用的是链表,如果多个线程,在某一时刻同时操作HashMap并执行put操作,而有大于两个key的hash值相同,这个时候需要解决碰撞冲突,而解决冲突的办法上面已经说过,对于链表的结构在这里不再赘述,暂且不讨论是从链表头部插入还是从尾部初入,这个时候两个线程如果恰好都取到了对应位置的头结点e1,而最终的结果可想而知,a1、a2两个数据中势必会有一个会丢失,put方法不是同步的,同时调用了addEntry方法,addEntry方法依然不是同步的,所以导致了线程不安全出现伤处

HashMap存在扩容的情况,对应的方法为HashMap中的resize方法,扩容方法也不是同步的,通过代码我们知道在扩容过程中,会新生成一个新的容量的数组,然后对原数组的所有键值对重新进行计算和写入新的数组,之后指向新生成的数组
当多个线程同时检测到总数量超过门限值的时候就会同时调用resize操作,各自生成新的数组并rehash后赋给该map底层的数组table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会有问题



Q12:写一个单例模式的程序,说说设计模式有哪些?单例模式和工厂模式啥区别?


			
  1.  


		
  1. public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) {  
            instance = new Singleton();  
        } return instance;  
        }  
    
    } 
    https://blog.csdn.net/column/details/jason0539-shejimoshi.html

#实习#
全部评论
雷霆新秀,火箭旧将,远景实习生~ 到了秋招就能看出来啦~
点赞 回复
分享
发布于 2018-04-05 14:00
static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } // 第二题 HashMap的一个方法 O(1)
点赞 回复
分享
发布于 2018-04-11 23:30
滴滴
校招火热招聘中
官网直投
***感觉好难啊
点赞 回复
分享
发布于 2018-07-15 21:42
厉害了word球
点赞 回复
分享
发布于 2018-04-04 16:56
实习or校招
点赞 回复
分享
发布于 2018-04-04 16:58
远景要现场面的吗?
点赞 回复
分享
发布于 2018-04-04 18:28
投的是甚么岗呢
点赞 回复
分享
发布于 2018-04-05 13:53
666
点赞 回复
分享
发布于 2018-04-11 23:26

相关推荐

头像
点赞 评论 收藏
转发
点赞 91 评论
分享
牛客网
牛客企业服务