• java深入学习(一) 2015-09-11 10:45:45
    为什么接口要规定成员变量必须是public static final的呢? 答: 首先接口是一种高度抽象的”模版”,,而接口中的属性也就是’模版’的成员,就应当是所有实现”模版”的实现类的共有特性,所以它是public static的...
    1. 为什么接口要规定成员变量必须是public static final的呢?
    答:
    首先接口是一种高度抽象的"模版",,而接口中的属性也就是’模版’的成员,就应当是所有实现"模版"的实现类的共有特性,所以它是public static的 ,是所有实现类共有的 .假如可以是非static的话,因一个类可以继承多个接口,出现重名的变量,如何区分呢?
    
    其次,接口中**如果可能定义非final的变量的话,而方法又都是abstract的,这就自相矛盾**了,有**可变成员变量但对应的方法却无法操作这些变量**,虽然可以直接修改这些静态成员变量的值,但所有实现类对应的值都被修改了,这跟抽象类有何区别? 又接口是一种更高层面的抽象,是一种规范、功能定义的声明,所有可变的东西都应该归属到实现类中,这样接口才能起到标准化、规范化的作用。所以接口中的属性必然是final的。
    
    最后,接口只是对事物的属性和行为更高层次的抽象 。对**修改关闭,对扩展(不同的实现implements)开放**,接口是对开闭原则(Open-Closed Principle )的一种体现。
    
    - 接口的所有成员都应该公开,所以是 public(我觉得因为接口必须被他类实现,所以必须为public) 
    - 接口不能实例化,所以只有静态成员: static(非static成员变量必须通过对象进行操作,而接口不能实例化,所以只能为static) 
    - 接口的成员一定应该是常量,所以是 final。(这个正如上面所解释的,如果接口的成员是变量,而一旦实现的类改变了该值,则所有实现类都被改变了,因为static)
    
     interface 在设计角度上通俗的定义standard(标注),从面向对象来说我们可以把它看做一个USB接口,所以:
        -  既然是标准,那就应该向外开放,于是接口的所有成员都应该 public
        -  既然是标准,那就不能轻易改变,而且要满足开放性,于是变量需要static (满足开放性),final(满足不可变性)
    
    总而言之,接口是一种高级抽象的规范,它设计的宗旨就是 不可修改,只可扩展!
    
    2.  Java集合类详解:
    http://blog.csdn.net/softwave/article/details/4166598
    
    3.  java中HashSet详解
    http://alex09.iteye.com/blog/539549
    
    4.  hashmap实现原理
    http://www.cnblogs.com/xwdreamer/archive/2012/05/14/2499339.html
    
    5.  字节流与字符流
    ![这里写图片描述](https://img-blog.csdn.net/20150911100143908)
    
    ![这里写图片描述](http://www.blogjava.net/images/blogjava_net/sinojava/etc/42135.gif)
    
    ![这里写图片描述](http://www.blogjava.net/images/blogjava_net/sinojava/etc/42136.gif)
    
    ![这里写图片描述](http://www.blogjava.net/images/blogjava_net/sinojava/etc/42137.gif)
    
    6.  volatile:
    - volatile关键字的两层语义
      一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
      1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
      2)禁止进行指令重排序。
      先看一段代码,假如线程1先执行,线程2后执行:
    
    			//线程1
    			boolean stop = false;
    			while(!stop){
    				doSomething();
    			}
    			
    			//线程2
    			stop = true;
    	
     这段代码是很典型的一段代码,很多人在中断线程时可能都会采用这种标记办法。但是事实上,这段代码会完全运行正确么?即一定会将线程中断么?不一定,也许在大多数时候,这个代码能够把线程中断,但是也有可能会导致无法中断线程(虽然这个可能性很小,但是只要一旦发生这种情况就会造成死循环了)。
    
      下面解释一下这段代码为何有可能导致无法中断线程。在前面已经解释过,每个线程在运行过程中都有自己的工作内存,那么线程1在运行的时候,会将stop变量的值拷贝一份放在自己的工作内存当中。
    
      那么当线程2更改了stop变量的值之后,但是还没来得及写入主存当中,线程2转去做其他事情了,那么线程1由于不知道线程2对stop变量的更改,因此还会一直循环下去。
    
      但是用volatile修饰之后就变得不一样了:
      第一:使用volatile关键字会强制将修改的值立即写入主存;
    
      第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量stop的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);
    
      第三:由于线程1的工作内存中缓存变量stop的缓存行无效,所以线程1再次读取变量stop的值时会去主存读取。
    
      那么在线程2修改stop值时(当然这里包括2个操作,修改线程2工作内存中的值,然后将修改后的值写入内存),会使得线程1的工作内存中缓存变量stop的缓存行无效,然后线程1读取时,发现自己的缓存行无效,它会等待缓存行对应的主存地址被更新之后,然后去对应的主存读取最新的值。
      那么线程1读取到的就是最新的正确的值。
    
    - volatile保证原子性吗?
    
      从上面知道volatile关键字保证了操作的可见性,但是volatile能保证对变量的操作是原子性吗?
    
      下面看一个例子:
    
    			public class Test {
    			    public volatile int inc = 0;
    			     
    			public void increase() {
    			        inc++;
    			}
    		     
    		    public static void main(String[] args) {
    		        final Test test = new Test();
    		        for(int i=0;i1)  //保证前面的线程都执行完
    		            Thread.yield();
    		        System.out.println(test.inc);
    		    }
    		}
       大家想一下这段程序的输出结果是多少?也许有些朋友认为是10000。但是事实上运行它会发现每次运行结果都不一致,都是一个小于10000的数字。
    
      可能有的朋友就会有疑问,不对啊,上面是对变量inc进行自增操作,由于volatile保证了可见性,那么在每个线程中对inc自增完之后,在其他线程中都能看到修改后的值啊,所以有10个线程分别进行了1000次操作,那么最终inc的值应该是1000*10=10000。
    
      这里面就有一个误区了,volatile关键字能保证可见性没有错,但是上面的程序错在没能保证原子性。可见性只能保证每次读取的是最新的值,**但是volatile没办法保证对变量的操作的原子性**。
    
      在前面已经提到过,**自增操作是不具备原子性的**,它包括读取变量的原始值、进行加1操作、写入工作内存。那么就是说自增操作的三个子操作可能会分割开执行,就有可能导致下面这种情况出现:
    
      假如某个时刻变量inc的值为10,
    
      线程1对变量进行自增操作,线程1先读取了变量inc的原始值,然后线程1被阻塞了;
    
      然后线程2对变量进行自增操作,线程2也去读取变量inc的原始值,由于线程1只是对变量inc进行读取操作,而没有对变量进行修改操作,所以不会导致线程2的工作内存中缓存变量inc的缓存行无效,所以线程2会直接去主存读取inc的值,发现inc的值时10,然后进行加1操作,并把11写入工作内存,最后写入主存。
    
      然后线程1接着进行加1操作,由于已经读取了inc的值,注意此时在线程1的工作内存中inc的值仍然为10,所以线程1对inc进行加1操作后inc的值为11,然后将11写入工作内存,最后写入主存。
    
      那么两个线程分别进行了一次自增操作后,inc只增加了1。
    
      解释到这里,可能有朋友会有疑问,不对啊,前面不是保证一个变量在修改volatile变量时,会让缓存行无效吗?然后其他线程去读就会读到新的值,对,这个没错。这个就是上面的happens-before规则中的volatile变量规则,但是要注意,线程1对变量进行读取操作之后,被阻塞了的话,并没有对inc值进行修改。然后虽然volatile能保证线程2对变量inc的值读取是从内存中读取的,但是线程1没有进行修改,所以线程2根本就不会看到修改的值。
    
      根源就在这里,**自增操作不是原子性操作**,而且**volatile也无法保证对变量的任何操作都是原子性的**。
    
      把上面的代码改成以下任何一种都可以达到效果:
      采用synchronized:
    
    			public class Test {
    		    public  int inc = 0;
    	    
    		    public synchronized void increase() {
    		        inc++;
    		    }
    	    
    		    public static void main(String[] args) {
    		        final Test test = new Test();
    		        for(int i=0;i1)  //保证前面的线程都执行完
    		            Thread.yield();
    		        System.out.println(test.inc);
    		    }
    		    }
    
    - volatile能保证有序性吗?
    
      在前面提到volatile关键字能禁止指令重排序,所以volatile能在一定程度上保证有序性。
    
      volatile关键字禁止指令重排序有两层意思:
    
      1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;
    
      2)在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。
    
      可能上面说的比较绕,举个简单的例子:
      //x、y为非volatile变量
    //flag为volatile变量
     
    			x = 2;        //语句1
    			y = 0;        //语句2
    			flag = true;  //语句3
    			x = 4;         //语句4
    			y = -1;       //语句5
    由于flag变量为volatile变量,那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2前面,也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5的顺序是不作任何保证的。
    
      并且volatile关键字能保证,执行到语句3时,语句1和语句2必定是执行完毕了的,且语句1和语句2的执行结果对语句3、语句4、语句5是可见的。
    
      那么我们回到前面举的一个例子:
    			 
    			//线程1:
    					context = loadContext();   //语句1
    					inited = true;             //语句2
    					
    			//线程2:
    			while(!inited ){
    			  sleep()
    			}
    			doSomethingwithconfig(context);
    			
    前面举这个例子的时候,提到有可能语句2会在语句1之前执行,那么久可能导致context还没被初始化,而线程2中就使用未初始化的context去进行操作,导致程序出错。
    
      这里如果用volatile关键字对inited变量进行修饰,就不会出现这种问题了,因为当执行到语句2时,必定能保证context已经初始化完毕。
    ***
    下面这段话摘自《深入理解Java虚拟机》:
    
      “观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
    
      lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
    
      1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
    
      2)它会强制将对缓存的修改操作立即写入主存;
    
      3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
    展开全文
  • 学习路线篇:如何快速高效学习javaSE学习视频和书籍推荐】写在前面的话:视频推荐书籍推荐:总结 写在前面的话: 本文章适用于想要学习java基础知识,且想知道如何快速高效学习的同学,我会在这里分享自己学习的...
  • 一集合框架  (1)集合的概念  现实生活中的集合:很多的事物凑在一起。  数学中的集合:具有共同属性的事物的总体。  Java中的集合类:是一种工具类,就像是容器,储存任意数量的具有共同属性的对象。...
  • JavaSE学习笔记_1:Java概述 2016-04-24 18:23:20
    1、Java语言的引入JavaSE学习笔记:Java概述  首先,我们与计算机进行交流就需要一种媒介,这种媒介就是我们所熟悉的一个名词—软件。软件?软件就是一系列按照特定顺序组织的计算机数据和指令的集合。软件可分为...
  • JavajavaSE部分1)能够掌握DOS系统常用基本命令;2)熟练使用eclipse编写java代码;3)掌握常用数据结构和算法;4)掌握常用的编程设计模式;5)熟练使用java语言的常用对象;6)使用java编写单机应用程序;...
  • JavaSE 学习经验汇总 2018-12-14 09:42:19
    学习Java的内存分配机制和内存泄漏问题 Java Platform Standard Edition 面向对象概念的理解、Java基本语法的学习,Java桌面图形界面应用程序的开发,掌握常用的Java API等(关键是要学会怎样查阅)。 重点:...
  • 如何学习JAVASE 2017-06-09 21:25:30
    1.实践很重要,多写代码 ...JAVASE中真正能用到的有: Java 是典型的服务器端的语言,所以不要在SWING 和AWT上浪费你宝贵的时间 1.集合框架 2. OOD 万物皆对象,好好理解,深入理解 3. 泛型
  • 写在前面 关于为什么要在现在系统的学习...选择什么课程:这里的话我是选择了刘意老师的深入浅出精华版为主,毕向东老师的Java基础教程为辅来进行学习。 这里给出刘意老师视频的B站地址:https://www.bilibili.c...
  • JavaSE及MySQL学习资料 2013-06-22 11:10:42
    Java多线程编程详解 ... 点击打开链接 ...深入JVM锁机制1--synchronized http://blog.csdn.net/chen77716/article/details/6618779 点击打开链接  Java手机版API文档 http://www.
  • 例如当将MySQL数据库转换成Oracle数据库时(个人简单的见解,深入探究请忽略) 业务逻辑模块 /* *业务逻辑模块 *通过接口实现数据库的操作 */ public class Logic01 { DaoService dao;//定义操作数据库的...
  • 刚入门时学了一个学期的Java,零零碎碎的学了个大概,等到后面学习深入的东西时发现漏洞百出,特意深入学习一下JavaSE 前言 Java分为JavaME 、JavaSE、 JavaEE 1.Java SE(Java Platform,Standard Edition) ...
  • 形式参数和返回值的问题深入研究:形式参数:形式参数分为基本类型和引用类型。引用类型:类:需要的是该类的对象,也可以用匿名对象来作为参数和调用的主体。抽象类:子类实现对象。创建该抽象类的具体子类,然后用...
  • 接上文《JavaSE 基础学习之一 —— Java 的简介》 二. Java 的部分基本语法 注:本篇文章部分记录时,老师默认我们有较佳的编程功底,故该部分讲的不深入,所以本篇笔记整理的比较简单随意。 1. 类 类的...
  • 今天既然我们学习Java的Socket网络通信编程,那么在我们的现实生活中那些是Socket编程的应用呢?可以想象 我们最常用的聊天工具软件QQ就是,当然MSN也是啦。  一网络基础知识  两台计算机通过网络进行通信的必要...
  • javaSE注解的学习 2013-12-11 02:17:54
    javase是基础,注解在我们java学习道路中是很常见的,在座web开发的时候就会用到。 注解的使用方便了我们开发。 下面就简单演示下注解的定义和对注解中德属性进行赋值并取出来。 创建注解类:...
  • 本文将告诉你学习Java需要达到的30个目标,学习过程中可能遇到的问题,及学习路线。希望能够对你的学习有所帮助。对比一下自己,你已经掌握了这30条中的多少条了呢? 路线 Java发展到现在,按应用来分主要分为三大...
  • 一. Java 的简介 1. 安装 JDK JDK 是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的 java 应用程序。JDK 是整个 java 开发的核心,它包含了 JAVA 的运行环境( JVM + Java 系统类库)和 JAVA ...
  • [转]JavaSE学习 Swing(一) 2013-07-30 13:07:56
    本章将会深入Swing面向菜单的组件。菜单与工具栏通过提供一些可视化的命令选项可以使得我们的程序更为友好。尽管Swing组件可以支持多个按键的命令序列,菜单被设计用来提供使用鼠标的图形化选择,而不是通过键盘。 ...
  • ------- android培训、java培训、期待与您交流! ---------- 一、抽象类 当一个类被abstract关键字修饰了之后,该类就是抽象类 抽象类的特点: ①方法只有声明,没有实现的时候,该方法就是抽象方法,需要被...
  • 传智播客刘意-风清扬的JavaSE学习资料,共有27天,视频和源码都有,下载后打开记事本复制链接密码,下载即可
1 2 3 4 5 ... 20
收藏数 5,445
精华内容 2,178