2018-03-18 部分问题日记

sql中in和exist两者的区别

  1. in和exists一般搭配子查询来使用,in的话也可以单独的使用in(a,b,c...)这种方式来使用;
  2. in关键字会先执行子查询即对内表的查询,再与外表做笛卡尔积(即若外表有1000条记录,内表有100,则会生成1000*100条记录),再根据条件筛选数据,而exists会先执行外表查询,再进行内外的条件判断筛选结果(外表结果集为100,则内表的子查询会执行100次);
  3. 两者对索引的使用也存在不同,使用in关键字时,使用的是外表的索引,而exists则是使用的内表的索引;所以当外表较大,使用外表索引,子查询内表结果较小的时候,使用in的效率会更高,而当外表较小,而子查询内表结果较大,且子查询使用索引的时候,使用exists效率会更高,若内外表查询结果集相差不大,两者效率基本相持,可根据所使用的索引来确定具体使用的关键字;
  4. in中子查询结果会放入内存,进行条件判断是在内存中进行的,而exists每一次的内外条件相比较是在数据库中完成的;

举个例子,下列有如下两个表


t_user

t_order表

有如下两条SQL

--使用in关键字
SELECT *
FROM t_user 
WHERE id IN (
    SELECT user_id
    FROM t_order 
);

--使用exists关键字
SELECT t.*
FROM t_user t
WHERE EXISTS (
    SELECT tt.user_id
    FROM t_order tt
    WHERE t.id = tt.user_id
)

最后输出的结果是一致的


sql的结果

IN

首先分析使用in关键字的sql,执行这条sql首先会先执行子查询即内表t_order表的查询

SELECT user_id FROM t_order

然后与外表的查询生成一个笛卡尔积


生成的结果集(未筛选)

然后根据sql中的条件将t_user的id和t_order的user_id进行比较,不相等的记录被删除,最后输出对应的结果集。

EXISTS

使用exists的语句,与in不同,他会默认先查询外表的查询

SELECT t.* FROM t_user t
外表查询结果集

然后在根据外表查询结果的每一行,与子查询内表执行一次,若子查询的条件符合(本例sql即t_user的id和t_order的user_id相等),则返回true,若不符合则返回false,则删除外表查询结果集中的一行,最后完成筛选

EXISTS (
    SELECT tt.user_id
    FROM t_order tt
    WHERE t.id = tt.user_id
)

例子中外表和内表的查询数据都差不多,但是外表查询用到了主键id,主键同时也是默认创建的索引,而内表查询中未使用索引,可使用in关键字

注意:in关键字不对null进行处理,not in是不会使用索引的,会对内外表进行全扫描,所以效率极低,而not exists仍会使用内表的索引

2、Java反射机制介绍

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java中使用反射一般是通过Class类这个对象来完成,JavaAPI中的描述如下:

Class对象

这个类没有构造方法,Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。Class对象下有很多方法,下面介绍一部分常用的方法。
参考:http://blog.csdn.net/sinat_38259539/article/details/71799078

String str = new String("demo");//新建一个String对象
//常用的Class对象获取方式
Class cla = str.getClass();
cla = String.class;
cla = Class.forName("java.lang.String"); //通过类的真实路径来返回一个Class类,一般使用这个,可以动态获取所需要的Class对象

Object obj = cla.newInstance(); //通过newInstance返回实例

//获取对应类、接口的构造函数
Constructor[] cons  =cla.getConstructors(); //获取所有的public的构造函数
Constructor con  = cla.getConstructor(int.class); //获取对应参数类型的public构造函数,class入参可变
cons  = cla.getDeclaredConstructors(); //获取所有构造函数
con  = cla.getDeclaredConstructors(char.class); //获取对应入参类型的所有构造函数

//获取对应类、接口的成员变量
Field[] fields = cla.getFields(); //获取所有的public成员变量
Field field = cla.getField("demo"); //获取对应名称public成员变量
field.set(obj, "demo"); //对应静态变量进行赋值,参数:1、实例,2、修改后的数据
fields = cla.getDeclaredFields();
field = cla.getDeclaredField("demo");

//获取类、接口下的成员方法
Method[] methods = cla.getMethods(); //获取所有的public成员方法
Method method = cla.getMethod("demo", String.class); //获取对应名称的public成员方法
methods = cla.getDeclaredMethods();
method = cla.getDeclaredMethod("demo", String.class);
method.invoke(obj, "demo"); //调用方法,入参:第一个实例,第二个对应的是入参
 
//调用main函数
method = cla.getMethod("main", String[] args);
method.invoke(obj, (Object)new String[]{"d","e","m","o"});

3、获得实例中的new和newInstance的区别

  1. 两者加载的构造器不同,new关键字可以调用任意的pulbic构造器,newInstance只能调用无参构造器;
  2. 用new关键字时,类可以没有被加载,而使用newInstance必须保证类已经被加载了;
  3. new,强类型,相对高效,newInstance,弱类型,低效率;
  4. new关键字完成了类加载、类的实例化,而newInstance则需要手动完成类加载,Class.forName("java.lang.String")这行代码完成了类的加载;
  5. newInstance可以通过传入ClassName来动态的加载类的实例,而不需要显式的调用类的构造器
//用new创建对象,可以调用无参或者有参的public构造函数
String str1 = new String();

//用newInstance
Class cla = Class.forName("java.lang.String"); //初始化,完成类的加载
Object obj = cla.newInstance(); //实例化
String str2 = (String)obj; //向下转型为子类

4、单例模式中饿汉模式和懒汉模式的区别

共同特点:构造器为私有化
(1)、懒汉模式:延迟加载,当被使用时才会加载,“时间换空间策略”,单纯的懒汉模式是非线程安全的,若有多个线程同时进入getInstance方法,线程1先进入if代码块后,线程二同时控制代码,会造成两个实例被返回,可以通过使用静态内部类(静态内部类在外部类加载时会进行初始化)或者双重检查(静态变量上需添加volatile,由于指令重排问题会导致线程不安全)的方式来达到线程安全的要求
(2)、饿汉模式:类加载时,实例已经完成,存放于内存中,“空间换时间”策略,线程安全

饿汉模式

public class SingletonDemo1(){
      private static SingletonDemo1 singletonDemo1 = new SingletonDemo1();      
      private SingletonDemo1(){
            //私有构造函数
      }
      private static SingletonDemo1 getInstance(){
              return singletonDemo1;
      }
}

懒汉模式

public class SingletonDemo2(){
      private static SingletonDemo2 singletonDemo2 = null;      
      private SingletonDemo2(){
            //私有构造函数
      }
      private static SingletonDemo2 getInstance(){
             if(singletonDemo2  == null){ //懒汉单例模式的实例未被创建
                 singletonDemo2  = new SingletonDemo2();
             }
            return singletonDemo2 ;
      }
}

懒汉模式-双重检查

public class SingletonDemo2(){
      private static volatile SingletonDemo2 singletonDemo2 = null;      
       private SingletonDemo2(){
            //私有构造函数
      }
      private static SingletonDemo2 getInstance(){
             if(singletonDemo2  == null){ //懒汉单例模式的实例未被创建
                 synchronized(SingletonDemo2.class){ 
                     if(singletonDemo2  == null){
                          singletonDemo2  = new SingletonDemo2();
                     }
                  }
             }
            return singletonDemo2 ;
      }
}

Holder式,通过静态内部类实现懒加载

public class Singleton {
    private static class SingletonHolder{
        static {
            System.out.println("单例内部类被初始化");
        }
                private static Singleton singleton = new Singleton();
        private SingletonHolder(){
            System.out.println("单例内部类构造函数调用");
        }
    }
    
    private Singleton(){
        System.out.println("静态内部类调用外部类的私有构造函数");
        if (SingletonHolder.singleton !=null) {
            try {
                throw new IllegalAccessException("单例对象已经被实例化,请不要非法反射构造函数");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static Singleton getInstance(){
        return SingletonHolder.singleton;
    }
}

Holder懒加载结果

public class SingleTonTest { //测试Holder的懒加载
    public static void main(String[] args) throws ClassNotFoundException  {
        System.out.println("类载入---------");
        Class cla = Class.forName("demo.Singleton"); //完成单例类的加载
        System.out.println("类载入完成------"+cla);
        System.out.println("获取单例实例-----");
        Singleton singleton = Singleton.getInstance(); //获取单例类的实例
        System.out.println("获取单例结束-----"+singleton);
    }
}

控制台输出结果


执行顺序
  1. 可以从输出结果中看到在完成单例类加载的时候,静态内部类并未被初始化,此时单例类的唯一实例还未被调用创建,不会占用内存空间。
  2. 在获取单例实例时,即静态内部类被调用时,静态内部类首先完成了初始化,调用了外部类的构造函数生成实例,完成懒加载;
  3. 此方法在实现懒加载的同时,亦保证了线程安全,且未使用synchronized悲观锁,性能好
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,608评论 18 399
  • 一. Java基础部分.................................................
    wy_sure阅读 3,808评论 0 11
  • 转 # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    吕品㗊阅读 9,714评论 0 44
  • 1、水的一生 水,可以是水,也可以是冰,是蒸汽。 放在杯子里,被人喝掉,是一生;化作山间流水,源源不断,又是一生。...
    蓝柿阅读 330评论 4 4
  • 追赶火车于我而言,真算得上经验丰富了。 周五的下午,脑子里便策划坐哪趟车,往往担心临时有事故意把时...
    吴二水_bf67阅读 315评论 1 1