Android初级工程师面试题答案——Java题型

面试题答案(按照以上往下的顺序依次排序):

Java类型题目:

1.网上搜索的思想

定义临时变量min,max,把他们都赋值数组的第1位,开启for循坏,让数组中每个数都和变量min和max比,如果比变量小或者大的话,就把比变量小或者大的数,赋值给对应的临时变量,for循环结束后,变量min和max此时的值就是最小与最大的。

    @Test
    public void test1() {
        int[] arr = new int[]{6, 78, 12, 65, 0,89, 98, 56, 32, 84};
        int[] minMax = minMax(arr);
        System.out.println(Arrays.toString(minMax));
    }

    private static int[] minMax(int[] arr) {
        int[] minMax;
        int min = arr[0], max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] < min){
                min = arr[i];
            }
            if (arr[i] > max){
                max = arr[i];
            }
        }
        minMax = new int[]{min, max};
        return minMax;
    }

    //增强for循环
    private static int[] minMax(int[] arr) {
        int[] minMax;
        int min = arr[0], max = arr[0];
        for (int anArr : arr) {
            if (anArr < min) {
                min = anArr;
            }
            if (anArr > max) {
                max = anArr;
            }
        }
        minMax = new int[]{min, max};
        return minMax;
    }

2.参考网站: https://blog.csdn.net/hello_zhou/article/details/70048503

自己的思想:将字符串拆成char数组,开启for循环,按照下标变量i依次往后比较,不相同则往sb加入相比的c[i],相同则跳过,但到了最后几位的时候需要再做判断,比如“sdsffsdfaffww”,会有4种不同的情况:

倒数第三和第二不相同:倒数第二和最后一个相同:只往sb中添加最后一个;倒数第二和最后一个不相同:往最后两个一起都添加到sb中。

倒数第三和第二相同:无论倒数第二和最后一个相同不相同,都只往sb中添加最后一个

//写一个函数,从一个字符串中剔除连续的字符,只留一个。
    @Test
    public void test2() {
        String str = "abbbccduiojrognesiofssssflkaioapopppsadasffww";
        String str2 = removeContinuous(str);
        System.out.println(str2);
    }

    //自己的想法  面试的时候没电脑想不出封装的方法只能拆成字符数组来慢慢比
 private static String doFilter(String str) {
        char[] c = str.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < c.length - 1; i++) {
            if (c[i] != c[i + 1]) {
                sb.append(c[i]);
            }
            if (i == c.length - 2) {
                if (c[i - 1] != c[i]) {
                    if (c[i] != c[i + 1]) {
                        sb.append(c[i]);
                        sb.append(c[i + 1]);
                    } else {
                        sb.append(c[i + 1]);
                    }
                } else if (c[i - 1] == c[i]) {
                    sb.append(c[i + 1]);
                }
            }
        }
        return sb.toString();
    }

网上搜索的思想

第一种:从前面往后面遍历,定义两个下标变量i、j,i代表要追加进去的字符下标,j代表往后遍历可移动的下标变量,然后首先第一个一定要先添加进sb中,不然第一二个一样的话就会直接跳过,不会添加进去;进入循环后,如果i与j下标对应的字符值相同,就跳过让变量j自增1,代表下一次循环要比较的字符下标,进入下一次循环后,i与j下标对应的字符再次进行比较,相同再执行同样的操作,不相同的时候就先把j的值赋给i,j再在i的基础上加1(而不是自增1,这里要注意),然后把j赋给i的变量对应的字符值添加到sb中进去,最后循环结束后,sb中的值就是剔除连续的字符。

//写一个函数,从一个字符串中剔除连续的字符,只留一个。
    @Test
    public void test2() {
        String str = "aabbbccduiojrognesiofssssflkaioapopppsadasffww";
        String str2 = removeContinuous(str);
        System.out.println(str2);
    }


    //第一种,从前往后遍历,如果后面的字符与当前的字符相同,就直接跳过,如果不相同,就停止。
    private String doFilter1(String str) {
        StringBuilder sb = new StringBuilder();
        int i = 0;
        int j = 1;
        sb.append(str.charAt(i));
        while (j < str.length()) {
            if (str.charAt(i) == str.charAt(j)) {
                j++;
            } else {
                i = j;
                j = i + 1;
                sb.append(str.charAt(i));
            }
        }
        return sb.toString();
    }


    // 第二种,是只比较当前字符与前一个字符是否相等,如果相等就删除前一个字符,不相等则直接向下遍历。
    private String doFilter2(String string) {
        StringBuilder sb = new StringBuilder(string);
        for (int i = 1; i < sb.length(); i++) {
            if (sb.charAt(i) == sb.charAt(i - 1)) {
                sb.deleteCharAt(i - 1);
                i--;
            }
        }
        return sb.toString();
    }

第二种 :将str传入sb中,int i =1(目的避免下标越界)遍历,进入循环后,将i与i前一个下标进行比较,如果相同则使用sb中的deleteCharAt()方法删除i前面一个下标的字符,并将i--(目的是删除后sb的长度发生改变,下标重新洗牌,i--可以让下次循环时保持遍历的顺序不会打乱跳过),然后再进入循环,不相同则变量继续i++,直至退出,最后循环结束后,sb中的值就是剔除连续的字符。

    //写一个函数,从一个字符串中剔除连续的字符,只留一个。
    @Test
    public void test2() {
        String str = "aadasffasdasfgesfaaaa";
        String str2 = doFilter2(str);
        System.out.println(str2);
    }


    // 第二种,是只比较当前字符与前一个字符是否相等,如果相等就删除前一个字符,不相等则直接向下遍历。
    private String doFilter2(String str) {
        StringBuilder sb = new StringBuilder(str);
        for (int i = 1; i < sb.length(); i++) {
            if (sb.charAt(i) == sb.charAt(i - 1)) {
                sb.deleteCharAt(i - 1);
                i--;
            }
        }
        return sb.toString();
    }

 

3.

 

4.参考网站: https://www.cnblogs.com/yuanting/p/4756632.html

Java语言中一共有八大基本数据类型(所占字节):

  • 整型:byte(1) short(2) int(4) long(8) 
  • 浮点型:float(4) double(8)
  • 字符型:char(2)
  • 布尔型:boolean(1)

(关于boolean占几个字节,众说纷纭,虽然boolean表现出非0即1的“位”特性,但是存储空间的基本计量单位是字节,不是位。所以boolean至少占一个字节。 
JVM规范中,boolean变量作为int处理,也就是4字节;boolean数组当做byte数组处理。)

5. 参考网站:  https://blog.csdn.net/qq_20919247/article/details/80891209

2 << 7

主要考的是位运算符,2的二进制是00000010,128的二进制是10000000,所以2 << 7 左移7位是最有效率的 

6.参考网站:https://blog.csdn.net/u012110719/article/details/46316659   https://blog.csdn.net/sinat_19687693/article/details/41692499

在switch(expr1)中,expr1只能是一个整数表达式或者枚举常量(更大字体),整数表达式可以是int基本类型或Integer包装类型,由于,byte,short,char都可以隐含转换为int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long和String类型都不符合switch的语法规定,并且不能被隐式转换成int类型,所以,它们不能作用于swtich语句中。
 

switch可作用:byte short int char 和它们对应的包装类 

 switch不可作用:float double long boolean和它们的包装类 String(JDK1.7之后才可以作用在string上)

答案:switch可以作用在char,因为它可以隐式转int符合语法规定;不可以作用在long,因为它不可以隐式转int不符合语法规定;switch可以作用在String,jdk1.7以后可以作用在String上。

7.参考网站:http://www.gulixueyuan.com/course/39/task/475/show http://www.importnew.com/7010.html

区别:

1、HashMap允许使用null作为键值对,而Hashtable不允许使用nul作为键值对

2、HashMap是线程不安全的,而Hashtable线程安全

3、HashMap遵循驼峰命名格式,而Hashtable没有

4、Hashtable是古老的Map实现类,从jdk1.0就有了,而HashMap不是

5、HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

6、由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。

7、HashMap不能保证随着时间的推移Map中的元素次序是不变的。

8.参考网站: https://blog.csdn.net/yuzongtao/article/details/83306182  https://www.cnblogs.com/songanwei/p/9386749.html

   注解原理:

1,注解声明(这4个元注解都是在jdk的java.lang.annotation包下面)

  • @Target(ElementType是一个枚举类定义注解可以作用的类型上所修饰的对象范围,比如属性、方法、包等等)

  • @Retention(定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)使用这个元注解可以对 Annotation的“生命周期”限制)

  • @Documented(用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员)

  • @Inherited(元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类

    注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

    当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层)

2,使用注解的元素

使用注解没什么好说的就是在你需要的地方加上对应的你写好的注解就行

3,操作注解使其起作用(注解处理器)

这个是注解使用的核心了,前面我们说了那么多注解相关的,那到底java是如何去处理这些注解的呢

从getAnnotation进去可以看到java.lang.class实现了AnnotatedElement方法

MyAnTargetType t = AnnotationTest.class.getAnnotation(MyAnTargetType.class);
public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement
java.lang.reflect.AnnotatedElement接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:

  方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
  方法2:Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
     方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
  方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响

反射原理:

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

Class 类与java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了Field,Method,Constructor类(每个类都实现了Member 接口)。这些类型的对象时由JVM 在运行时创建的,用以表示未知类里对应的成员。

这样你就可以使用Constructor 创建新的对象,用get() 和set() 方法读取和修改与Field 对象关联的字段,用invoke() 方法调用与Method 对象关联的方法。另外,还可以调用getFields() getMethods() 和 getConstructors() 等很便利的方法,以返回表示字段,方法,以及构造器的对象的数组。这样匿名对象的信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

用我自己的话总结就是:Class是反射的源头,有了Class的实例以后,我们可以创建对应运行时类的对象、获取对应运行时类的完整结构、调用对应运行时类的指定的结构。

具体可以参考鄙人的博客:https://blog.csdn.net/Peter__Li/article/details/89096852

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值