zoukankan      html  css  js  c++  java
  • 整理最近面试遇到的一些问题

    最近在求职,陆陆续续会有很多面试,现在凭想象力记下来,总结自己面试中回答不太好的地方:

    18/08/13 周一 上午 ,云途

    1.如何将给定的字符串内容反转?即倒序

    该问题,当时回答不是很好,回来后自己敲了下,发现自己不足.以下列出四种解决方案:

    方案一:for循环遍历, 根据索引从后向前取字符串中的字符:

       public String reverse2(String value){
            if (value == null || value.length() < 2){
                return value;
            }
            String newValue = "";
            for (int i = (value.length() - 1); i >= 0; i--) {
                newValue += value.charAt(i);
            }
            return newValue;
        }

    方案二:将字符串转为char数组,然后倒叙取出每个字符,跟方案一类似:

        public String reverse3(String value){
            if (value == null || value.length() < 2){
                return value;
            }
            String newValue = "";
            char[] charArray = value.toCharArray();
            for (int i = (charArray.length- 1); i >= 0; i--) {
                newValue += charArray[i];
            }
            return newValue;
        }

    方案三:先将字符串转为StringBuilder 或者StringBuffer ,再利用二者的实例方法reverse,实现倒叙后 转为toString() ,这种方式最方便,不需要自己写方法

        public String reverse3(String value){
            if (value == null || value.length() < 2){
                return value;
            }
            return new StringBuffer(value).reverse().toString();
        }

    方案四:利用递归,将传入的字符串首个字符拼到末尾,同时截取字符串,依次递归,直到字符串长度为1

        public String reverse(String value){
            if (value == null || value.length() < 2){
                return value;
            }
            return reverse(value.substring(1)) + value.charAt(0);
        }

    2.现有两个ArrayList,需要将两个集合元素全部添加到一个集合中, 并且去除重复的元素,如何实现?

    思路:首先得到1个总的ArrayList,然后将ArrayList转为HashSet,利用HashSet的特性(元素不可重复)完成去重;

        @org.junit.Test
        public void name() {
            List<Integer> list1 = new ArrayList<>();
            List<Integer> list2 = new ArrayList<>();
    
            list1.add(1);
            list1.add(2);
            list1.add(3);
    
            list2.add(2);
            list2.add(3);
            list2.add(4);
    
            list1.addAll(list2);
            System.out.println(list1);
    
            //将List转为Set
            HashSet<Integer> set = new HashSet<>(list1);
            System.out.println(set);
    
            //也可以通过同样的方式将Set转为List
            System.out.println(new ArrayList<>(set));
        }

    原理是构造器可以接收Collection类型的对象:

     3.如何得到字符串去重后的长度? 例如:hello 去重后 是 helo ,长度也就是4;

        @org.junit.Test
        public void myTest() {
            String str = "Hello";
            Set<Object> hashSet = new HashSet<>();
    
            for (int i = 0; i < str.length(); i++) {
                hashSet.add(str.charAt(i));
            }
            System.out.println(hashSet.size());
        }

    也可以通过ArrayList完成,但是需要加一个contains的判断:

        @org.junit.Test
        public void myTest2() {
            String str = "Hello";
            List<Object> list = new ArrayList<>();
    
            for (int i = 0; i < str.length(); i++) {
                if (!list.contains(str.charAt(i))){
                    list.add(str.charAt(i));
                }
            }
            System.out.println(list.size());
        }

    4.上个问题中 ,contains(object)方法,判断list中是否已经存在某个元素,contains方法判断是否为同一个元素的原理是什么?

    答: ArrayList中有一个方法: indexOf(object) 如果object存在与list中,则返回大于相应的索引,否则返回-1

    如果indexOf()返回的值大于-1,则表示已存在,某则不存在;

    下面是contains方法与indexOf方法的源代码:

    public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }
    public int indexOf(Object o) {
            if (o == null) {
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }

    5.写出HashMap的迭代

        @org.junit.Test
        public void testHashMap() {
            Map<Object, Object> map = new HashMap<>();
            map.put("name","rye");
            map.put("location","GuangZhou");
            Set<Map.Entry<Object, Object>> entrySet = map.entrySet();
            for (Map.Entry<Object, Object> entry : entrySet) {
                System.out.println("key:"+entry.getKey() + " , value:"+entry.getValue());
            }
        }

    6.Spring中@Resourse 与 @Autowired的区别:

    注解的来源方面:

    @Resourse 是javax.annotation下的注解:

    @Autowired是org.springframework.beans.factory.annotation下的注解

    注解注入Bean的规则方面:

    @Service
    public class Demo{
    }
    
    //此时会寻找name为demo的Bean ,如果找不到就会报错
    @Resource(name="demo")
    Demo demo;
    
    //此时会寻找类型为Demo的bean,如果找不到或者找到了多于1个以上的Bean会抛错
    @Resource(type=Demo.class)
    Demo demo;
    
    //如果不指定Resource属性,则首先按照name查找,找不到再按type查找,再找不到就会抛错
    @Resource
    Demo demo;
    
    //=====================================================================
    //默认按照类型查找,如果找不到或找到不止1个就会报错 @Autowired Demo demo;

    //Autowired本身是没有name属性的,同时如果根据type找不到是不会再进行name的匹配的,不像Resource那样帮你做一个切换 /* 那么如果我就想用Autowried,而且还必须根据name注入,那应该怎么办呢? 此时仍有解决方案,需要搭配@Qualifier注解一起组合使用, */ @Autowired @Qualifier("demo") Demo demo;

    值得一提的是大多数情况下,通过注解建立的Bean,bean的name都为类名的首字母小写,但是并不是所有情况,bean的name都是类名首字母小写;
    例如:
    @Service
    public class Demo{}
    这时生成的name就为首字母小写,也就是:demo;

    但是下面这种情况生成bean的name并不是首字母小写
    @Service
    public class DEmo{}
    此时生成的name为: DEmo 而不是dEmo

    为什么会这样呢?此时需要查看下源码

    
    

     该方法名称也很直观表达出要构建默认的BeanName,再进一步看下 buildDefaultBeanName(definition, registry),做了什么事:

    由上图代码可知,先获取到该Bean的类名称(非全限定名),最终调用了Introspector.decapitalize(shortClassName) 处理类名,下面看下这个方法的细节:

     这也就解释了,为什么当类名为DEmo的时候,相应的beanName为DEmo,而不是dEmo

    7.请说下Java中的动态代理

    被问到这个问题,当时还是比较慌的,这块内容之前学习的时候有钻研过,但是后来工作中就很少去琢磨动态代理了

    关于动态代理的主要作用,我理解的是代理类(中介)对被代理类的一个增强

    假如:

    现在有一个车票的接口,里面暂时只有1个购票方法,如下:

    public interface ITicket {
        /**
         * 买票
         */
        void buyTicket();
    }

    旅客(class Passenger)是被代理类,实现了包含购票方法(buyTicket)的接口(interface ITicket) ;

    public class Passenger implements ITicket {
    
        private String name;
        private long idCardNumber;
    
        public Passenger(String name, long idCardNumber) {
            this.name = name;
            this.idCardNumber = idCardNumber;
        }
    
        public String getName() {
            return name;
        }
    
        public long getIdCardNumber() {
            return idCardNumber;
        }
    
        @Override
        public void buyTicket() {
            System.out.println("姓名为:"+this.name+",身份证号码为:"+this.idCardNumber+"的旅客通知,请扫码付钱...");
            System.out.println("...1S后拿到了票");
        }
    }

    旅客们更多的是关心买票的业务逻辑,至于买票之前的排队,旅客们都不想操作,他们宁愿找人排队,买到票后付点小费;

    所以此时就有个黄牛(代理类 class Scalper),他同样也实现了ITicket接口,拥有了买票的功能;同时在买票前排了队,买票成功后收取消费:

    但是你让我帮你买票,你得给我你得身份证呀,所以在黄牛类中需要拥有乘客的一个实例对象,如下:

    public class Scalper implements ITicket {
    
        //代理类中包含了1个被代理类的实例
        private Passenger passenger;
    
        public Scalper(Passenger passenger){
            this.passenger = passenger;
        }
    
    
        @Override
        public void buyTicket() {
            System.out.println("排队很久排到了..");
            passenger.buyTicket();
            System.out.println("乘客:"+passenger.getName()+" 请付20元");
        }
    }

    这样一来只需要将身份证交给黄牛即可帮你排队,买票(付钱肯定还是需要乘客自己付的),收取小费,下面是test:

    public class BuyTicketTest {
    
        @Test
        public void testByTicket() {
            Passenger rye = new Passenger("Rye", 10010L);
            Scalper scalper = new Scalper(rye);
            scalper.buyTicket();
        }
    }

    此时执行结果:

    排队很久排到了..
    姓名为:Rye,身份证号码为:10010的旅客通知,请扫码付钱...
    ...1S后拿到了票
    乘客:Rye 请付20元小费!

    通过上述举例,可以看出,代理类对被代理类中的方法进行了增强 , 代理类的主要目的也是如此

    由于描述能力有限,动态代理的原理并没有组织好合适的语言(后续会补上),仅仅是通过1个生活中常见的例子,来解释了下什么是代理;

    关于JDK动态代理这块更深的探讨以及原理请参阅此篇博客,个人觉得挺详细,深入浅出:https://www.cnblogs.com/gonjan-blog/p/6685611.html

    8.redis中常见的数据结构有哪些?

    共五种,并列举其中各个类型的简单的命令

    String字符串
      存:set name rye
      取:get rye
    List列表
      存:
        存入列表的左端:lpush list rye
        存入列表的右端:rpush list sherry
      根据index取:
        从左端取:lindex list 0      结果:rye
      范围取值,一次取多个:
        从左端取:lrange list 0 -1     (-1表示取到最后一位)  结果:rye  sherry
      弹出(删除):
        左端弹出:lpop list  结果:rye
        右端弹出:rpop list  结果:sherry    
     
    Set集合(元素不重复)
      存:sadd my_set rye   //添加成功返回1 ,如果已经存在则返回0
      取元素:smembers myset 
      判断元素是否在结合中:sismember myset rye  如果在集合中,则返回1,不在则返回0
      移除元素:srem myset rye  //如果set中包含这个元素则移除并返回1, 否则返回0
        
    Hash散列
      hash的value是key-value类型的值,结构如下:
      

      存储:hset myhash name rye  //如果新增的key-value中,key不在在则返回1,如果key存在,则更新value的值,返回0

      获取:

        获取hash中指定key的值:  hget myhash name     //存在则返回相应的值,不存在则返回nil

        获取hash中所有key-value:  hgetall  myhash       //如果集合不为空返回所有key-value,如果为空则返回提示empty list or set

      移除:hdel myhash name                //如果name存在则从myhash中移除,并返回1;否则返回0

     
    Zset有序集合:
      存储的也是一个映射,不过不同于Hash的是,存储的是元素与其分数的映射
      
      新增元素:  zadd my-score 100 math 70 english   ==> 2 //其中math,english表示存储的key,而分数相当于value;
                             //zadd 返回成功添加新元素的个数(已经存在元素不会统计),如果元素已经存在则更改分数.

        按照排名取元素: zrange my-score 0 -1 withscores ==> english   70  math 100  //按照score升序的顺序返回集合中的所有元素,并返回元素对应的分数,命令中withscores选项是可选的

      取出某个范围内的所有元素:  zrangebyscore my-score 80 100 withscores  ==> math 100 //取出某个分数值范围内的所有元素

      获取某个元素的排名:   zrank my-score math  ==> 2  //排序规则是按照分数递增,因此math在有序集合中的排名是2

      删除某个元素:      zrem my-score english ==>1 //移除成功返回1,反之返回0

    9.注解的原理是什么?

    10.ArrayList的本质是什么,什么情况下会进行扩容?每次扩容的大小是多少呢?

    List<String> list = new ArrayList(20);该语句执行了几次扩容?

    11.请书写出工厂设计模式的实现

    12.请描述Spring框架中的AOP,AOP的原理是什么,AOP在项目中的的应用范围有哪些

    持续更...

  • 相关阅读:
    .Net 开源项目资源大全
    无法向会话状态服务器发出会话状态请求
    网站限制不能点击右键
    ashx页面中context.Session["xxx"]获取不到值的解决办法
    SQL Server 2008 错误 233 的解决办法
    Best MVC Practices 最佳的MVC实践
    char* 转换成 CString
    MFC圆角背景移动边角底色毛刺解决方案
    CString转换为const char*
    分享一份安卓开发包,集成开发环境
  • 原文地址:https://www.cnblogs.com/lzzRye/p/9468177.html
Copyright © 2011-2022 走看看