- 浏览: 1081719 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (1055)
- quartz定时任务 (1)
- json (9)
- 接口 (1)
- http (1)
- sccket (2)
- xmlbean (1)
- webservice (1)
- flex (1)
- sitemesh (2)
- json组装 (2)
- 存储过程 (6)
- ajax后台返回前台上下问 (3)
- flect反射机制 (1)
- 页面列表 (1)
- oracal结果集合并 (1)
- lucene (1)
- 读取配置文件工具 (1)
- 框架整合 (1)
- jms (3)
- 断点续传 (1)
- 页面之间的传值 (1)
- jpa (6)
- sql (8)
- jsp跳转 (1)
- jsp (6)
- jquery (2)
- ui (1)
- js与jsp之间的值的交互应用 (1)
- js空值判断 (1)
- Ajax (9)
- web-inf 编译目录 (1)
- 多线程 (9)
- 资料 (0)
- oracal (4)
- 多线程webservice (1)
- ztree (1)
- 加载与内容的变化 (1)
- 页面的公用变量 (1)
- web-inf目录结构 (1)
- 登陆系列 (1)
- jass应用于webservice认证 (2)
- 路径问题 (1)
- list合并 (1)
- list map中的value获取 (2)
- 标签tag (4)
- 方法 (1)
- 树形数据及其渲染 (1)
- require js 回调 (1)
- tab 页面切换 (2)
- 计时获取验证码 (1)
- 模式 (6)
- easyui (3)
- dialog (2)
- 乱码问题 (1)
- spring (29)
- sqlserver (1)
- iis,netframework (0)
- iis (1)
- netframework (1)
- 处理乱码问题 (1)
- struts-ajax (0)
- ,理论,了;,; (0)
- 排错方法 (1)
- hibernate (1)
- 二级缓存 (1)
- portal (1)
- date类型 (0)
- jvm out of memery StackOverflowError (1)
- echart数据填充 (0)
- echart (1)
- jmv (1)
- 学习 (0)
- java基础 (1)
- oracle性能优化 (1)
- 数据库三范式 (1)
- easy UI (1)
- oracle11g (1)
- form (3)
- servlet (2)
- spring mvc (1)
- htm5 (0)
- ibatise (1)
- 序列化 (1)
- tomcat双认证 (1)
- maven Lib (1)
- tomcat eclipse (2)
- ehcache (1)
- http 代替 ajax (2)
- rest (6)
- script脚本占位模板 (1)
- strust 标签 el表达式 (1)
- js bo (1)
- 公司资料 (0)
- js return (1)
- spring 第三方插件的工具类 (1)
- linux (10)
- linux 克隆 (1)
- linux xshell连接 (1)
- yum expect (1)
- linux 应用命令 (1)
- yum 缓存rmp包 (1)
- yum 本地库离线安装 (2)
- yum错误 (1)
- jsp页面用定时调用 (1)
- ajax setup (2)
- Exception,RuntimeException (1)
- 对话框 dialog (1)
- maven (17)
- PropertyPlaceholderConfigurer properties文件 (1)
- 错误集 (1)
- mybatise (0)
- 拦截器filter (1)
- http get post 区别 (1)
- rest 客户端两种返回的数据处理方式 (1)
- listener (2)
- maven工程 (1)
- ContainerResponseFilter (1)
- ajax action 打印任意实体类jsp (1)
- yum svn mvn (1)
- 分页 (1)
- angularjs (1)
- memcached (1)
- git (12)
- yyyyyyyy (0)
- oracal安装 (4)
- jaxwswebservice (1)
- spring bean (1)
- 排方法 (0)
- java 生成pdf (2)
- 创建目录 (1)
- 下载与生产pdf文件 (1)
- base64 (2)
- 配置文件 (2)
- blob (1)
- pdf (1)
- yum linux 安装Oracle (1)
- excl 插入数据库 (1)
- 搭建框架 (1)
- .classpath和jdk jre (1)
- mybatise 配置文件通配 (1)
- 用Maven插件生成Mybatis代码 (2)
- springmvc值的传递 (1)
- js jsp html (1)
- ajax跨域 (1)
- javamail (0)
- 提交复杂格式json数据 (1)
- get中文乱码/post (1)
- 弹出框,承载弹出链接----页面,显示大图 (1)
- @RequestBody list bean (1)
- 隐藏域 (1)
- 多页保存 (1)
- form 校验 (1)
- 注册,上传图片 (1)
- 登录验证 (1)
- 全局的异常处理 (0)
- 异常捕获,显示在页面 (0)
- mybatise事物配置 (1)
- maven compile (1)
- 时间格式 (1)
- js 跳转页面 (1)
- pringsecurity 角色授资源要重启服务 (0)
- Retrofi restfull (1)
- session过期推出,直接点击退出,退出 (0)
- 参数放于requestbody (1)
- maven本地仓库jar包 (1)
- 编译环境出错jdk1.6 1,7 (1)
- jsonarray ---json数组格式 (1)
- java后台文件上传,接受的2种方式 (0)
- 生成保存图片 (1)
- 权限mysql数据库Md5加密sql (1)
- mysql一对多关联查询 (1)
- mysql批量更新 (0)
- oracle in exists 区别 (1)
- https (1)
- linux发布脚本 (1)
- dubbo zookeepr (1)
- request.getParameter() (1)
- request.setAttribute() (1)
- @RequestMapping @ResponseBody (1)
- @RequestMapping @responsebody src控件 后台如何写入src值 (1)
- dwz (8)
- lib jar maven (1)
- web服务访问名称 (1)
- mvc返回内容设置,拦截 (1)
- @ResponseBody 返回json处理 (1)
- 视图,函数,存储过程 (1)
- <context:annotation-config/> (1)
- <context:component-scan/> (1)
- xml路劲通配 (2)
- 杂项 (1)
- dubbo (34)
- redis (25)
- mybatis (34)
- springmvc (15)
- js (7)
- sprinvmvc (1)
- 设计理念 (1)
- 工程 (1)
- 其他 (149)
- 导出,下载 (1)
- session (4)
- token (1)
- Exception处理 (2)
- 注解 (2)
- 框架 (3)
- shrio (1)
- login (1)
- 项目结构设计 (1)
- mybatis两种关联查询 (1)
- mybaits (2)
- 迭代模式 (1)
- oralce树形数据结构构建 (2)
- 树形结构的jsp展现 (1)
- filter intecept(Struts) (1)
- 树形结构数据的提交 (1)
- @RequestBody @RequestParam (1)
- div (1)
- equals重写 (1)
- 程序设计 (1)
- f多层for循环跳出 (1)
- 看源码 (0)
- 权限系统普遍通性 (1)
- 设计程序 (1)
- 动态拼接元素样式问题 (1)
- sql迭代 (1)
- debug断点 (1)
- spring mvc 扫描注解(ioc (1)
- di) (1)
- jdk (2)
- cglib (1)
- mybatis 多层括号(超过三层)解析不了 (1)
- tiles (2)
- cacheManager缓存的切换 (1)
- jsp,xml中el表达式等占位符中的数据操作 (1)
- jpa 及spring data jpa开发 (1)
- compareTo equals toString (1)
- 子页面用父页面js (1)
- jsp相对路径自加问题 (1)
- bean之间的相互拷贝 (1)
- DECODE (2)
- 泛型 (2)
- NVL (1)
- jsp jstl函数 用标签声明页面变量,供jstl使用,时间格式问题 (1)
- form表单切换action值 (1)
- response.getWriter().write()功能优于springMvc的返回 (1)
- 快速复制构建项目 (1)
- activeMq (15)
- cache (2)
- sql获取序列号 (1)
- 上传 (2)
- tfs (1)
- jsp标签 (2)
- qita (1)
- 触发器 (1)
- Exception (1)
- mybais (1)
- 标签 (1)
- connect by (1)
- for ... in (1)
- map转化为list (1)
- 树形结构list构建(树形实体) (1)
- 左侧菜单的设计 (1)
- response.getWriter().write() (1)
- eclipse打断点之后断无效 (1)
- 直接访问/web-inf/下的页面 (1)
- clob (1)
- freemark (1)
- 框架的设计 (1)
- get方式处理乱码 (1)
- Request的getParameter和getAttribute方法的区别 (1)
- cas (9)
- 时间格式问题 (1)
- ResponseUtil.writeToResponse (1)
- 树形数据的反选 (1)
- spring data jpa (1)
- jsp异常提示 (1)
- jquery js (1)
- eclipse (1)
- 乱码 (1)
- Json OBJETC (1)
- PROCEDURE (1)
- pl/sql oracle (1)
- 设计 (1)
- el表达式 (3)
- iframe (1)
- map (1)
- jsp中调用Java (1)
- response.getWriter().write() ajax (1)
- mybatis xml 传入参数 (0)
- response与request在返回时作用区别 (1)
- spring cache (1)
- 模型驱动 (1)
- 关于mybatis传空值的处理 (1)
- 日志配置 (1)
- mapper (1)
- mapper mybatis (1)
- mapper mybatis-spring spring-data-jpa (1)
- js插件 (1)
- spring-data-jpa (2)
- 字节流转化过程 (1)
- 数据库 (11)
- jsp页面 (1)
- 局域网络访问问题 (1)
- plsql (2)
- response (1)
- plsq (1)
- Proxool (1)
- cas security (1)
- 系统配置化 (1)
- 集群 (4)
- springboot (24)
- 设计模式 (5)
- 通知 (1)
- 架构 (48)
- zookeeper (5)
- mvc框架 (1)
- 事物隔离策略 (1)
- jvm (8)
- 调研 (1)
- Java工具类 (1)
- 并发容器 (3)
- 多线程管理器 (4)
- 简历 (0)
- 查询 (1)
- 集群工具 (1)
- springMcv (1)
- ConcurrentHashMap (1)
- hashtable (1)
- cac (1)
- 树形结构 (1)
- 定时任务 (1)
- tortoiseGit (2)
- struts (11)
- shiro (31)
- log4j (3)
- struts2 (2)
- 编码 (1)
- request (3)
- Nginx (14)
- tomcat (1)
- idea (12)
- mvc (2)
- BeanUtils (2)
- image (1)
- mino (1)
- httpClient (1)
- volecity (1)
- swagger (3)
- 调错 (0)
- data (1)
- log (1)
- shell (1)
- 事物 (3)
- junit (1)
- RestTemplate (2)
- 线程 (0)
- Exception异常处理 (1)
- Exception异常注解 (1)
- lock (1)
- HashMap (1)
- 面试 (0)
- rabbitMq (1)
- rainCat (1)
- 其它 (1)
- activemq消息传送机制以及ACK机制详解 (0)
- mysql (7)
- fildder (1)
- UML (1)
- 校验 (1)
- 反射 (1)
- 切面 (1)
- springioc (1)
- urule2 (0)
- skywalking (1)
- urule (2)
- docker (2)
- 前端 (1)
- bootstrap (1)
- eureka (2)
- springcloud (16)
- jenkins (2)
- springsecurity (1)
- 数据结构 (4)
- gradle (1)
- mycat (3)
- nacos (1)
- canary (1)
- 线程池 (1)
- solr (1)
- resteasy (2)
- BI (1)
- dfs (2)
- elasticsearch (1)
- ruby (1)
- logstash (1)
- clickhouse (2)
- davinci (15)
- java (1)
- davinvi (1)
- fastdfs (1)
- vue (1)
- 《将博客搬至CSDN》 (1)
最新评论
-
nizhipeng123:
private SessionFactory sessio ...
用map接收参数的几个注意的问题
1重载:
当一个重载方法被调用时,Java 用参数的类型和(或)数量来表明实际调用的重载方法的版本。因此,每个重载方法的参数的类型和(或)数量必须是不同的。虽然每个重载方法可以有不同的返回类型,但返回类型并不足以区分所使用的是哪个方法。当Java 调用一个重载方法时,参数与调用参数匹配的方法被执行。
2,数值的自动转化识别:
OverloadDemo 的这个版本没有定义test(int) 。因此当在Overload 内带整数参数调用test()时,找不到和它匹配的方法。但是,Java 可以自动地将整数转换为double 型,这种转换就可以解决这个问题。因此,在test(int) 找不到以后,Java 将i扩大到double 型,然后调用test(double) 。当然,如果定义了test(int) ,当然先调用test(int) 而不会调用test(double) 。只有在找不到精确匹配时,Java 的自动转换才会起作用。
原则就是保证数值不丢失,失真。
3,构造函数重载:
当有有参数的构造函数的时候,没有再显示的写无参数构造函数,后面再调用无参数的构造函数会出错,只有再在程序中显示的申明无参数构造函数才可以。
4,接口,抽象类
接口继承接口(同类继承)
抽象类实现接口(异类实现)
抽象类,接口中的变量要是final,接口可以多实现是由于,同样的方法名不会报错只要有一个实现即可,抽象类就不同
子父类中的构造函数
在对子类对象进行初始化时,先运行父类的构造函数,再运行子类的构造函数。
因为子类的构造函数第一行有一个隐式的 super();会访问父类中的空参构造函数。
而且子类所有的构造函数,第一行都是super();
为什么子类一定要访问父类中的构造函数。
当父类中没有空参数构造函数时,子类必须显式调用super(参数);
因为父类中的数据子类可以直接获取,所以子类在建立时,需要查看父类是如何
进行初始化的,所以子类建立对象时,先访问一下父类的构造函数。
如果要访问父类中指定的构造函数,可以通过手动指定super();
注意:super语句一定定义在子类构造函数的第一行。
子类的实例化过程:
结论:子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类必须手动通过super或者this语句形式来指定
要访问的构造函数。
当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数。
其实构造函数也是一个链条一样的东西,会调用最上面的那层钩子,然后依次不重复的往下。每个构造函数虽然原理是先调用super,但是当构造函数形成一个链条的时候,不会每次去调用,就和js的原型差不多。
不重复即在调用链条的时候,不能重复调用super(),你手动调,在本构造函数不在调super,当你本构造函数又调用了其他在其他中会不显示调用也会默认调用super();
==============================
class B extends A
{
B()
{
// super(); //error ,错误
this(3);
System.out.println("B");
}
B(int x)
{
System.out.println("B2");
}
public static void main(String[] args)
{
B a=new B();
}
}
==============================
super 父类构造方法中第一条语句
子类不能继承父类的构造方法,更不能覆盖父类的构造方法。因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,而且必须使用关键字super来表示,而且super必须是子类构造方法中的头一条语句。
=====================================
//这里如果没有无参数的构造方法,而且显示的申明了有参数的构造方法,在子类中一定要显示调用父类的有参数构造方法,否则出错
class A{
public A(){} // 1:无参数构造方法。
public A(String s){} // 2.
}
class B extends A{
public B(String s){ super(s); // 3.
}
}
=====================================
static 在程序编译的时候就为变量分配内存地址,由这个类的所有对象共享, 直到程序停止运行,在接口的中的应用防止同名变量的覆盖,同名会被覆盖的原因是一个类中同一个变量指向同样的地址
final 表示变量的指向不变,但是里面的值可以修改
5 变量-内存-缓存寄存器
trainsent
决定javabean中的属性,不被序列化的字段,这个字段将不被持久化。
volatitle
在多线程中不把由此修饰符的变量缓存到寄存器中,直接在内存地址中取这个变量,比如一个线程用到了a,另一线程修改了a(肯定先在内存当中),如果用了这个字段那么前一个线程a的
值可以更新。
6,私有构造函数,单例模式
7,static 静态变量
静态这一词是正对类而言,与对象的观念排斥,它引用的只能是静态的脱离对象观念的变量,
一般的变量需要通过对象的形式获取,但是如果在静态块中自己重建了对象,先有了对象,才可以通过这个对象访问变量(这时候的变量就可以是动态变量),以对象的方式可以访问所有在类中的变量。只初始化一次,只有一份,在类被加载的时候
8,final
根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。
final类不能被继承,没有子类,final类中的方法默认是final的。(继承)
final方法不能被子类的方法覆盖,但可以被继承。(覆盖)
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。(地址不变,对象可以被修改)
final不能用于修饰构造方法。
注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
9,接口补充
变量不需申明,默认为public static final
方法不必申明,默认为public abstract
可以自加,但是有冲突就有问题
可以实现多个有共同方法的接口,实现了一个就实现了全部
public interface A {
int CONST = 1; //合法,CONST默认为public,static,final类型
void method(); //合法,method()默认为public,abstract类型
public abstract void method2(); //method2()显示声明为public,abstract类型
}
public interface A {
int var; //错,var是常量,必须显示初始化
void method(){...}; //错,接口中只能包含抽象方法
protected void method2(); //错,接口中的方法必须是public类型
static void method3(){...}; //错,接口中不能包含静态方法
}
抽象类中的变量子类中可以改变
数据库连接语句
drivermanager
Stringbuilder 与Stringbuffered
Stringbuffered线程安全
Stringbuilder不支持线程安全
arraylist 和 linkedlist Vector
arraylist线程不安全,
vector 线程安全
hashmap 和 hashtable
hashmap线程安全,hashtable线程不安全
静态内部内部类static class
内部不可以使用外部的东西,外部可以使用内部的东西,如果静态内部类要使用外部的变量,就需要在本类中new一个对象。之后通过对象的方式调用非静态变量。
jvm加载类的顺序
1,java lib
2,系统类加载器
3,用户自定义类加载器
单例模式私有的构造方法
不让外部实例化,直接用公共代码块里面的东西。这样就保证了变量的单例模式,不new东西。
/**
* 一个简单的死锁类
* @author iStar
* 当类的对象flag=1时(T1),先锁定O1,睡眠500毫秒,然后锁定O2;
* 而T1在睡眠的时候另一个flag=0的对象(T2)线程启动,先锁定O2,睡眠500毫秒,等待T1释放O1;
* T1睡眠结束后需要锁定O2才能继续执行,而此时O2已被T2锁定;
* T2睡眠结束后需要锁定O1才能继续执行,而此时O1已被T1锁定;
* T1、T2相互等待,都需要对方锁定的资源才能继续执行,从而死锁。
*/
class DeadLock implements Runnable {
public int flag = 1;
static Object o1 = new Object(), o2 = new Object();
@Override
public void run() {
System.out.println("flag=" + flag);
if(flag == 1) {
synchronized(o1) {//同步块
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o2) {
System.out.println("1");
}
}
}
if(flag == 0) {//同步块
synchronized(o2) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o1) {
System.out.println("0");
}
}
}
}
public static void main(String[] args) {
DeadLock td1 = new DeadLock();
DeadLock td2 = new DeadLock();
td1.flag = 1;
td2.flag = 0;
new Thread(td1).start();//其实可以直接开启,这个只是为了名称
new Thread(td2).start();
}
}
hashmap
键值可以为空,值可以一样,键也可以一样,同时取时后者覆盖前者
set 它是集合的形式保存,可以为空,有相同的只会保存一个
equal方法定义了对象相等的判定,比如属性相等,值相等,类型相等,
hashcode是将对象中的某些属性化为地址比较
如果equal的判定标准变了,hashcode的算法未变导致equal相等,hashcode不等
单例和线程安全是两回事
单例-只要拿到这个类就获得的是同一个对象。
多线程-在不同的线程操作同样的对象。
一个线程同步块中锁定对象相应的对象, 等同整个run方法执行完后这个线程释放执行完的同步块的对象,此时其他线程才可以使用这个对象(单例模式,或同一对象变量), 当然也可以用notify显示唤醒此想锁住此对象的其他之前没有得到锁的线程。
线程--对象--线程
java中内存分类:
1,堆heap
new 对象的销毁
spring的容器管理的对象管理
对象,存其地址。
手动申请分配的,手动回收
2,栈stack
普通变量,和对象的引用变量,由过了作用域就没用,申明了就自动分配可知
由jvm自动分配,自动回收
• Java把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
• 堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。
========================================================================
java class
其中加载是指将编译后的java类文件(也就是.class文件)中的二进制数据读入内存,并将其放在运行时数据区的方法区内,然后再堆区创建一个Java.lang.Class对象,用来封装类在方法区的数据结构。即加载后最终得到的是Class对象,并且更加值得注意的是:该Java.lang.Class对象是单实例的,无论这个类创建了多少个对象,他的Class对象时唯一的!!!!。 而 加载并获取该Class对象可以通过三种途径:
类的class对象是将类转化成class类的对象,一个类只有这么一个对象是单例的。
Class.forName(类的全路径)、实例对象.class(属性)、实例对象getClass()。关于他们的区别将在下面讲到!!!
###另外 ,类加载时类中的静态代码块会得到执行(详见前一篇博客:Class.forName()加载JDBC驱动
Class cl=A.class; JVM将使用类A的类装载器,将类A装入内存(前提是:类A还没有装入内存),不对类A做类的初始化工作.返回类A的Class的对象 ,这个class结构的的对象主要用来做反射机制,所以不必初始化 ,因为要做反射所以要是对象
Class.forName做初始化工作,这个主要用来接在jdbc等驱动,类似于web.xml加载监听一样
Class cl=对象引用o.getClass();返回引用o运行时真正所指的对象(因为:儿子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象,真正的对象,多态中的子类的classde 对象和.class一样,只是对于多态的情况更精准
.class前面的参数时类,.getclass前面的参数时对象
Class.forName("类名"); JAVA人都知道.装入类A,并做类的初始化,和上诉两者比多了初始化
,返回的是类,不是class类是对象,主要用于初始化
getClass()是动态的,其余是静态的。
.class和class.forName()只能返回类内field的默认值,getClass可以返回当前对象中field的最新值
Class.forName() 返回的是一个类,.newInstance() 后才创建一个对象,Class.forName()的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的
String className = readfromXMlConfig;//从xml 配置文件中获得字符串
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口,而struts2的Action是接口。
Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去 实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。
如何给一个特定的页面元素装载不同的样式
document.getElementById('ceil').className = "class1";
spring 面向方面编程(AOP)的实现原理,现场配置出来
Spring默认使用JDK动态代理实现AOP代理。这使得任何接口或 接口的集合能够被代理。
• HashMap 和 HashSet 有没有什么关联?HashMap与Hashtable的区别? 如何让HashMap同步?
• HashSEt就是hashMap
Map Collections.synchronizedMap(Map m)
这个方法返回一个同步的Map,这个Map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的
排序
冒泡
for(int i=a.length-1;i>0;--i)
{
for(int j=0;j<i;++j){
if(a[j+1]<a[j]) {
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
介绍Java的深度克隆和浅度克隆
不管是深度克隆还是浅度的克隆其实都是产生了一个新的对象。所以我们在比较克隆对象和源对象的时候返回是false。而深度克隆和浅度的克隆的区别在于:浅度克隆的对象只会克隆普通属性,不会克隆对象属性。而深度克隆就会连对象属性一起克隆。所以我们在对比深度克隆中的tt1.getChild()==tcbclone.getChild()时,返回是false。而浅度克隆时返回true。
深度克隆类:
所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。
对象的序列化还有另一个容易被大家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制大部分的对象,但是众所周知,Clone有深度Clone和浅度Clone,如果你的对象非常非常复杂,并且想实现深层 Clone,如果使用序列化,不会超过10行代码就可以解决。
虽然Java的序列化非常简单、强大,但是要用好,还有很多地方需要注意。比如曾经序列化了一个对象,可由于某种原因,该类做了一点点改动,然后重新被编译,那么这时反序列化刚才的对象,将会出现异常。 你可以通过添加serialVersionUID属性来解决这个问题。如果你的类是个单例(Singleton)类,是否允许用户通过序列化机制复制该类,如果不允许你需要谨慎对待该类的实现。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class DepthClone {
public final static Object objectCopy(Object oldObj) {
Object newObj = null;
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(oldObj);//源对象
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi= new ObjectInputStream(bi);
newObj = oi.readObject();//目标对象
} catch (IOException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
return newObj;
}
}
浅度克隆类:
对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象
1、实现java.lang.Cloneable接口
要clone的类为什么还要实现Cloneable接口呢?Cloneable接口是一个标识接口,不包含任何方法的!这个标识仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的 clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出 CloneNotSupportedException异常。(有了实现这个标识接口,就可以用clone)
2、重写java.lang.Object.clone()方法
JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。(对于大的第一层对象,而不是属性对象,属性对象是一个引用)
观察一下Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。Object类中的clone()还是一个protected属性的方法,重写之后要把clone()方法的属性设置为public。
Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。
//大对象
import java.io.Serializable;
public class SimpleClone implements Cloneable ,Serializable {
private static final long serialVersionUID = -7552721152118950502L;
public String s = null;
public Object o = null;
public CloneObject cloneObject = null;
public SimpleClone(CloneObject cloneObject) {
this.cloneObject = cloneObject;
}
public Object clone() {
SimpleClone newSimpleClone = null;
try {
/* 浅克隆 */
newSimpleClone = (SimpleClone)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return newSimpleClone;
}
}
克隆对象://深度克隆和浅度克隆的区别就在于此(大对象中的属性对象)
import java.io.Serializable;
public class CloneObject implements Serializable{
private static final long serialVersionUID = 4332788486669750696L;
private String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
克隆测试:
public class TestClone {
public static void main(String[] arg) {
CloneObject obj1 = new CloneObject();
obj1.setName("cloneOne");
CloneObject obj2 = new CloneObject();
obj2.setName("cloneTwo");
SimpleClone simpleClone1 = new SimpleClone(obj1);
SimpleClone simpleClone2 = new SimpleClone(obj2);
simpleClone1.s = "simpleClone1";
simpleClone1.o = "simpleClone1Object";
//simpleClone2 = (SimpleClone)simpleClone1.clone();
simpleClone2 = (SimpleClone)DepthClone.objectCopy(simpleClone1);
/* 如果是浅克隆, simpleClone1中的cloneObject会随着simpleClone2的cloneObject改变面改变*/
simpleClone2.cloneObject.setName("cloneThree");
System.out.println(simpleClone1.cloneObject.getName());
System.out.println(simpleClone2.cloneObject.getName());
}
}
Oracle SQL性能优化
(1) 选择最有效率的表名顺序(只在基于规则的优化器中有效):
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.
(2) WHERE子句中的连接顺序.:
ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.
(3) SELECT子句中避免使用 ‘ * ‘:
ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间
(4) 减少访问数据库的次数:
ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等;
(5) 在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200
(6) 使用DECODE函数来减少处理时间:
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.
(7) 整合简单,无关联的数据库访问:
如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系)
(8) 删除重复记录:
最高效的删除重复记录方法 ( 因为使用了ROWID)例子:
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
(9) 用TRUNCATE替代DELETE:
当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况) 而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. (译者按: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML)
(10) 尽量多使用COMMIT:
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少:
COMMIT所释放的资源:
a. 回滚段上用于恢复数据的信息.
b. 被程序语句获得的锁
c. redo log buffer 中的空间
d. ORACLE为管理上述3种资源中的内部花费
(11) 用Where子句替换HAVING子句:
避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销. (非oracle中)on、where、having这三个都可以加条件的子句中,on是最先执行,where次之,having最后,因为on是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,where也应该比having快点的,因为它过滤数据后才进行sum,在两个表联接时才用on的,所以在一个表的时候,就剩下where跟having比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where可以使用rushmore技术,而having就不能,在速度上后者要慢如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,根据上篇写的工作流程,where的作用时间是在计算之前就完成的,而having就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。在多表联接查询时,on比where更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where进行过滤,然后再计算,计算完后再由having进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里
(12) 减少对表的查询:
在含有子查询的SQL语句中,要特别注意减少对表的查询.例子:
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
(13) 通过内部函数提高SQL效率.:
复杂的SQL往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的
(14) 使用表的别名(Alias):
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.
java 流
//管子一层套一层具有更特殊的功能
Java语言的输入输出功能是十分强大而灵活的,对于数据的输入和输出操作以“流”(stream)的方式进行。J2SDK提供了各种各样的“流”类,用以获取不同种类的数据,定义在包java.io中。程序中通过标准的方法输入或输出数据。
Java中的流可以从不同的角度进行分类:
按照流的方向不同:分为输入流和输出流。
按照处理数据单位的不同:分为字节流(8位)和字符流(16位)。
按照功能不同:分为节点流和处理流。
节点流:是可以从一个特定的数据源(节点)读写数据的流(例如文件,内存)。就像是一条单一的管子接到水龙头上开始放水。
处理流:是“连接”在已经存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。就像在已经接了一条管子(节点流)的基础上,又套上几个更粗,具有特殊功能的管子(处理流)对流出的水进一步的处理。
queue队列 和 堆栈stack
queue队列先进先出, 堆栈先进后出。
不用拼接sql,使用参数的好处
主要在于防止sql注入,一个变量在传递的时候只会传递一个值,有sql注入的情况会被检查出错误
拼接字符串不会检查输入是否合理,只要语法没问题就会被拼接
如:select * from aaaa where N=(拼接的内容) 这个语句如果符合SQL语法就会被执行
但如果人们输入select * from aaaa where N=('N' or 1=1) 时,无论N是否等于N,sql都会执行通过。这就是漏洞……
N=N or 1=1 无论任何时候 1都是=1的……
而执行参数传入时,只有一个合法的参数是可以被传入的……而(N=N or 1=1)这种情况是不被允许的……(不符合变量 N的类型)
大量数据的储存
http://www.codesky.net/article/201002/167897.html
1,分批多次提交commit
2,多次flash
3,线程sleep()
4,用存储过程,数据存储代替系统处理
threadlocal 互补多线程中共享变量的共享同步,具有threadlocal结构的变量可以以不同的副本在个线程单独使用
ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程” 。其实,ThreadLocal并不是一个 Thread,而是 Thread 的局部变量,也许把它命名为 ThreadLocalVariable更容易让人理解一些。当使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。
另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。
如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。
JDK 5 以后提供了泛型支持,ThreadLocal 被定义为支持泛型:
public class ThreadLocal<T> extends Object
T 为线程局部变量的类型。该类定义了 4 个方法:
1) protected T initialValue():返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。 该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。
2)public T get():返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用 initialValue() 方法返回的值。
3)public void set(T value):将此线程局部变量的当前线程副本中的值设置为指定值。大部分子类不需要重写此方法,它们只依靠 initialValue() 方法来设置线程局部变量的值。
4)public void remove():移除此线程局部变量当前线程的值。如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法重新初始化其值。这将导致在当前线程多次调用 initialValue 方法。
下面是一个使用 ThreadLocal 的例子,每个线程产生自己独立的序列号。就是使用ThreadLocal存储每个线程独立的序列号复本,线程之间互不干扰。
package sync;
public class SequenceNumber {
// 定义匿名子类创建ThreadLocal的变量
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
// 覆盖初始化方法
public Integer initialValue() {
return 0;
}
};
// 下一个序列号
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
//私有的静态内部类在使用外部的非静态变量的时候要通过new对象的方式去用,不能直接用
private static class TestClient extends Thread {
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
// 线程产生序列号
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]");
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
SequenceNumber sn = new SequenceNumber();
// 三个线程产生各自的序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
}
程序的运行结果如下:
thread[Thread-1] sn[1]
thread[Thread-1] sn[2]
thread[Thread-1] sn[3]
thread[Thread-2] sn[1]
thread[Thread-2] sn[2]
thread[Thread-2] sn[3]
thread[Thread-0] sn[1] thread[Thread-0] sn[2]
thread[Thread-0] sn[3]
//单例模式的对象变量要私有的原因在于,只在内部赋值,外部要用这个变量只能通过get方法获取,防止其他地方篡改,构造函数私有的原因是为了总是一个对象,其他的地方不能new这个对象。
syschronized修饰的是静态的代码块,锁定的是调用这个方法的类,而不是对象。
//多线程的状态
当调用了start方法之后只是就绪状态,有cpu的时候才会运行
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
public class Test1 extends Thread{
public void run(){
System.out.println("Test:run()");
}
public void start(){
System.out.println("Test:start()");
}
public class Test2 implements Runnable{
public void run(){
System.out.println("Test2:run()");
}
public void start(){
System.out.println("Test2:start()");
}
}
public class TestThread {
public static void main(String[] args) {
//重写了父类的方法,所以只有子类起作用
Test1 t1 = new Test1();
//再包一层表示后续调用的如有重名覆盖的比如start,那么是调用线程里的,这里也重写了父类的方法,但是包了一层之后,用的是thread对象,此时的start是此对象的,不再有包了。
Thread t2 = new Thread(new Test2());
t1.start();//这个调用了那个类中的方法,而不是启动线程
t2.start();//这个调用了线程,这是为什么要包一层的原因
}
}
结果输出:
Test:start()
Test2:run()
直接调用run方法此时调用的不是线程,而是方法,这个线程还是主线程
请注意,当使用 runnable 接口时,您不能直接创建所需类的对象并运行它;必须从 Thread 类的一个实例内部运行它。许多程序员更喜欢 runnable 接口,因为Java多线程编程从 Thread 类继承会强加类层次。 包成thread
java中的数据类型,可分为两类:
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
他们之间的比较,应用双等号(==),比较的是他们的值。
2.复合数据类型(类)
当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
当一个重载方法被调用时,Java 用参数的类型和(或)数量来表明实际调用的重载方法的版本。因此,每个重载方法的参数的类型和(或)数量必须是不同的。虽然每个重载方法可以有不同的返回类型,但返回类型并不足以区分所使用的是哪个方法。当Java 调用一个重载方法时,参数与调用参数匹配的方法被执行。
2,数值的自动转化识别:
OverloadDemo 的这个版本没有定义test(int) 。因此当在Overload 内带整数参数调用test()时,找不到和它匹配的方法。但是,Java 可以自动地将整数转换为double 型,这种转换就可以解决这个问题。因此,在test(int) 找不到以后,Java 将i扩大到double 型,然后调用test(double) 。当然,如果定义了test(int) ,当然先调用test(int) 而不会调用test(double) 。只有在找不到精确匹配时,Java 的自动转换才会起作用。
原则就是保证数值不丢失,失真。
3,构造函数重载:
当有有参数的构造函数的时候,没有再显示的写无参数构造函数,后面再调用无参数的构造函数会出错,只有再在程序中显示的申明无参数构造函数才可以。
4,接口,抽象类
接口继承接口(同类继承)
抽象类实现接口(异类实现)
抽象类,接口中的变量要是final,接口可以多实现是由于,同样的方法名不会报错只要有一个实现即可,抽象类就不同
子父类中的构造函数
在对子类对象进行初始化时,先运行父类的构造函数,再运行子类的构造函数。
因为子类的构造函数第一行有一个隐式的 super();会访问父类中的空参构造函数。
而且子类所有的构造函数,第一行都是super();
为什么子类一定要访问父类中的构造函数。
当父类中没有空参数构造函数时,子类必须显式调用super(参数);
因为父类中的数据子类可以直接获取,所以子类在建立时,需要查看父类是如何
进行初始化的,所以子类建立对象时,先访问一下父类的构造函数。
如果要访问父类中指定的构造函数,可以通过手动指定super();
注意:super语句一定定义在子类构造函数的第一行。
子类的实例化过程:
结论:子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类必须手动通过super或者this语句形式来指定
要访问的构造函数。
当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数。
其实构造函数也是一个链条一样的东西,会调用最上面的那层钩子,然后依次不重复的往下。每个构造函数虽然原理是先调用super,但是当构造函数形成一个链条的时候,不会每次去调用,就和js的原型差不多。
不重复即在调用链条的时候,不能重复调用super(),你手动调,在本构造函数不在调super,当你本构造函数又调用了其他在其他中会不显示调用也会默认调用super();
==============================
class B extends A
{
B()
{
// super(); //error ,错误
this(3);
System.out.println("B");
}
B(int x)
{
System.out.println("B2");
}
public static void main(String[] args)
{
B a=new B();
}
}
==============================
super 父类构造方法中第一条语句
子类不能继承父类的构造方法,更不能覆盖父类的构造方法。因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,而且必须使用关键字super来表示,而且super必须是子类构造方法中的头一条语句。
=====================================
//这里如果没有无参数的构造方法,而且显示的申明了有参数的构造方法,在子类中一定要显示调用父类的有参数构造方法,否则出错
class A{
public A(){} // 1:无参数构造方法。
public A(String s){} // 2.
}
class B extends A{
public B(String s){ super(s); // 3.
}
}
=====================================
static 在程序编译的时候就为变量分配内存地址,由这个类的所有对象共享, 直到程序停止运行,在接口的中的应用防止同名变量的覆盖,同名会被覆盖的原因是一个类中同一个变量指向同样的地址
final 表示变量的指向不变,但是里面的值可以修改
5 变量-内存-缓存寄存器
trainsent
决定javabean中的属性,不被序列化的字段,这个字段将不被持久化。
volatitle
在多线程中不把由此修饰符的变量缓存到寄存器中,直接在内存地址中取这个变量,比如一个线程用到了a,另一线程修改了a(肯定先在内存当中),如果用了这个字段那么前一个线程a的
值可以更新。
6,私有构造函数,单例模式
7,static 静态变量
静态这一词是正对类而言,与对象的观念排斥,它引用的只能是静态的脱离对象观念的变量,
一般的变量需要通过对象的形式获取,但是如果在静态块中自己重建了对象,先有了对象,才可以通过这个对象访问变量(这时候的变量就可以是动态变量),以对象的方式可以访问所有在类中的变量。只初始化一次,只有一份,在类被加载的时候
8,final
根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。
final类不能被继承,没有子类,final类中的方法默认是final的。(继承)
final方法不能被子类的方法覆盖,但可以被继承。(覆盖)
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。(地址不变,对象可以被修改)
final不能用于修饰构造方法。
注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。
9,接口补充
变量不需申明,默认为public static final
方法不必申明,默认为public abstract
可以自加,但是有冲突就有问题
可以实现多个有共同方法的接口,实现了一个就实现了全部
public interface A {
int CONST = 1; //合法,CONST默认为public,static,final类型
void method(); //合法,method()默认为public,abstract类型
public abstract void method2(); //method2()显示声明为public,abstract类型
}
public interface A {
int var; //错,var是常量,必须显示初始化
void method(){...}; //错,接口中只能包含抽象方法
protected void method2(); //错,接口中的方法必须是public类型
static void method3(){...}; //错,接口中不能包含静态方法
}
抽象类中的变量子类中可以改变
数据库连接语句
drivermanager
Stringbuilder 与Stringbuffered
Stringbuffered线程安全
Stringbuilder不支持线程安全
arraylist 和 linkedlist Vector
arraylist线程不安全,
vector 线程安全
hashmap 和 hashtable
hashmap线程安全,hashtable线程不安全
静态内部内部类static class
内部不可以使用外部的东西,外部可以使用内部的东西,如果静态内部类要使用外部的变量,就需要在本类中new一个对象。之后通过对象的方式调用非静态变量。
jvm加载类的顺序
1,java lib
2,系统类加载器
3,用户自定义类加载器
单例模式私有的构造方法
不让外部实例化,直接用公共代码块里面的东西。这样就保证了变量的单例模式,不new东西。
/**
* 一个简单的死锁类
* @author iStar
* 当类的对象flag=1时(T1),先锁定O1,睡眠500毫秒,然后锁定O2;
* 而T1在睡眠的时候另一个flag=0的对象(T2)线程启动,先锁定O2,睡眠500毫秒,等待T1释放O1;
* T1睡眠结束后需要锁定O2才能继续执行,而此时O2已被T2锁定;
* T2睡眠结束后需要锁定O1才能继续执行,而此时O1已被T1锁定;
* T1、T2相互等待,都需要对方锁定的资源才能继续执行,从而死锁。
*/
class DeadLock implements Runnable {
public int flag = 1;
static Object o1 = new Object(), o2 = new Object();
@Override
public void run() {
System.out.println("flag=" + flag);
if(flag == 1) {
synchronized(o1) {//同步块
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o2) {
System.out.println("1");
}
}
}
if(flag == 0) {//同步块
synchronized(o2) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o1) {
System.out.println("0");
}
}
}
}
public static void main(String[] args) {
DeadLock td1 = new DeadLock();
DeadLock td2 = new DeadLock();
td1.flag = 1;
td2.flag = 0;
new Thread(td1).start();//其实可以直接开启,这个只是为了名称
new Thread(td2).start();
}
}
hashmap
键值可以为空,值可以一样,键也可以一样,同时取时后者覆盖前者
set 它是集合的形式保存,可以为空,有相同的只会保存一个
equal方法定义了对象相等的判定,比如属性相等,值相等,类型相等,
hashcode是将对象中的某些属性化为地址比较
如果equal的判定标准变了,hashcode的算法未变导致equal相等,hashcode不等
单例和线程安全是两回事
单例-只要拿到这个类就获得的是同一个对象。
多线程-在不同的线程操作同样的对象。
一个线程同步块中锁定对象相应的对象, 等同整个run方法执行完后这个线程释放执行完的同步块的对象,此时其他线程才可以使用这个对象(单例模式,或同一对象变量), 当然也可以用notify显示唤醒此想锁住此对象的其他之前没有得到锁的线程。
线程--对象--线程
java中内存分类:
1,堆heap
new 对象的销毁
spring的容器管理的对象管理
对象,存其地址。
手动申请分配的,手动回收
2,栈stack
普通变量,和对象的引用变量,由过了作用域就没用,申明了就自动分配可知
由jvm自动分配,自动回收
• Java把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
• 堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。
========================================================================
java class
其中加载是指将编译后的java类文件(也就是.class文件)中的二进制数据读入内存,并将其放在运行时数据区的方法区内,然后再堆区创建一个Java.lang.Class对象,用来封装类在方法区的数据结构。即加载后最终得到的是Class对象,并且更加值得注意的是:该Java.lang.Class对象是单实例的,无论这个类创建了多少个对象,他的Class对象时唯一的!!!!。 而 加载并获取该Class对象可以通过三种途径:
类的class对象是将类转化成class类的对象,一个类只有这么一个对象是单例的。
Class.forName(类的全路径)、实例对象.class(属性)、实例对象getClass()。关于他们的区别将在下面讲到!!!
###另外 ,类加载时类中的静态代码块会得到执行(详见前一篇博客:Class.forName()加载JDBC驱动
Class cl=A.class; JVM将使用类A的类装载器,将类A装入内存(前提是:类A还没有装入内存),不对类A做类的初始化工作.返回类A的Class的对象 ,这个class结构的的对象主要用来做反射机制,所以不必初始化 ,因为要做反射所以要是对象
Class.forName做初始化工作,这个主要用来接在jdbc等驱动,类似于web.xml加载监听一样
Class cl=对象引用o.getClass();返回引用o运行时真正所指的对象(因为:儿子对象的引用可能会赋给父对象的引用变量中)所属的类的Class的对象,真正的对象,多态中的子类的classde 对象和.class一样,只是对于多态的情况更精准
.class前面的参数时类,.getclass前面的参数时对象
Class.forName("类名"); JAVA人都知道.装入类A,并做类的初始化,和上诉两者比多了初始化
,返回的是类,不是class类是对象,主要用于初始化
getClass()是动态的,其余是静态的。
.class和class.forName()只能返回类内field的默认值,getClass可以返回当前对象中field的最新值
Class.forName() 返回的是一个类,.newInstance() 后才创建一个对象,Class.forName()的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的
String className = readfromXMlConfig;//从xml 配置文件中获得字符串
class c = Class.forName(className);
factory = (ExampleInterface)c.newInstance();
Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口,而struts2的Action是接口。
Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去 实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。
如何给一个特定的页面元素装载不同的样式
document.getElementById('ceil').className = "class1";
spring 面向方面编程(AOP)的实现原理,现场配置出来
Spring默认使用JDK动态代理实现AOP代理。这使得任何接口或 接口的集合能够被代理。
• HashMap 和 HashSet 有没有什么关联?HashMap与Hashtable的区别? 如何让HashMap同步?
• HashSEt就是hashMap
Map Collections.synchronizedMap(Map m)
这个方法返回一个同步的Map,这个Map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的
排序
冒泡
for(int i=a.length-1;i>0;--i)
{
for(int j=0;j<i;++j){
if(a[j+1]<a[j]) {
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
介绍Java的深度克隆和浅度克隆
不管是深度克隆还是浅度的克隆其实都是产生了一个新的对象。所以我们在比较克隆对象和源对象的时候返回是false。而深度克隆和浅度的克隆的区别在于:浅度克隆的对象只会克隆普通属性,不会克隆对象属性。而深度克隆就会连对象属性一起克隆。所以我们在对比深度克隆中的tt1.getChild()==tcbclone.getChild()时,返回是false。而浅度克隆时返回true。
深度克隆类:
所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。
对象的序列化还有另一个容易被大家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制大部分的对象,但是众所周知,Clone有深度Clone和浅度Clone,如果你的对象非常非常复杂,并且想实现深层 Clone,如果使用序列化,不会超过10行代码就可以解决。
虽然Java的序列化非常简单、强大,但是要用好,还有很多地方需要注意。比如曾经序列化了一个对象,可由于某种原因,该类做了一点点改动,然后重新被编译,那么这时反序列化刚才的对象,将会出现异常。 你可以通过添加serialVersionUID属性来解决这个问题。如果你的类是个单例(Singleton)类,是否允许用户通过序列化机制复制该类,如果不允许你需要谨慎对待该类的实现。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class DepthClone {
public final static Object objectCopy(Object oldObj) {
Object newObj = null;
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(oldObj);//源对象
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi= new ObjectInputStream(bi);
newObj = oi.readObject();//目标对象
} catch (IOException e) {
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
return newObj;
}
}
浅度克隆类:
对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象
1、实现java.lang.Cloneable接口
要clone的类为什么还要实现Cloneable接口呢?Cloneable接口是一个标识接口,不包含任何方法的!这个标识仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的 clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出 CloneNotSupportedException异常。(有了实现这个标识接口,就可以用clone)
2、重写java.lang.Object.clone()方法
JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。(对于大的第一层对象,而不是属性对象,属性对象是一个引用)
观察一下Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。Object类中的clone()还是一个protected属性的方法,重写之后要把clone()方法的属性设置为public。
Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。
//大对象
import java.io.Serializable;
public class SimpleClone implements Cloneable ,Serializable {
private static final long serialVersionUID = -7552721152118950502L;
public String s = null;
public Object o = null;
public CloneObject cloneObject = null;
public SimpleClone(CloneObject cloneObject) {
this.cloneObject = cloneObject;
}
public Object clone() {
SimpleClone newSimpleClone = null;
try {
/* 浅克隆 */
newSimpleClone = (SimpleClone)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return newSimpleClone;
}
}
克隆对象://深度克隆和浅度克隆的区别就在于此(大对象中的属性对象)
import java.io.Serializable;
public class CloneObject implements Serializable{
private static final long serialVersionUID = 4332788486669750696L;
private String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
克隆测试:
public class TestClone {
public static void main(String[] arg) {
CloneObject obj1 = new CloneObject();
obj1.setName("cloneOne");
CloneObject obj2 = new CloneObject();
obj2.setName("cloneTwo");
SimpleClone simpleClone1 = new SimpleClone(obj1);
SimpleClone simpleClone2 = new SimpleClone(obj2);
simpleClone1.s = "simpleClone1";
simpleClone1.o = "simpleClone1Object";
//simpleClone2 = (SimpleClone)simpleClone1.clone();
simpleClone2 = (SimpleClone)DepthClone.objectCopy(simpleClone1);
/* 如果是浅克隆, simpleClone1中的cloneObject会随着simpleClone2的cloneObject改变面改变*/
simpleClone2.cloneObject.setName("cloneThree");
System.out.println(simpleClone1.cloneObject.getName());
System.out.println(simpleClone2.cloneObject.getName());
}
}
Oracle SQL性能优化
(1) 选择最有效率的表名顺序(只在基于规则的优化器中有效):
ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.
(2) WHERE子句中的连接顺序.:
ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.
(3) SELECT子句中避免使用 ‘ * ‘:
ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间
(4) 减少访问数据库的次数:
ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等;
(5) 在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200
(6) 使用DECODE函数来减少处理时间:
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.
(7) 整合简单,无关联的数据库访问:
如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系)
(8) 删除重复记录:
最高效的删除重复记录方法 ( 因为使用了ROWID)例子:
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
(9) 用TRUNCATE替代DELETE:
当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况) 而当运用TRUNCATE时, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. (译者按: TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML)
(10) 尽量多使用COMMIT:
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少:
COMMIT所释放的资源:
a. 回滚段上用于恢复数据的信息.
b. 被程序语句获得的锁
c. redo log buffer 中的空间
d. ORACLE为管理上述3种资源中的内部花费
(11) 用Where子句替换HAVING子句:
避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销. (非oracle中)on、where、having这三个都可以加条件的子句中,on是最先执行,where次之,having最后,因为on是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,where也应该比having快点的,因为它过滤数据后才进行sum,在两个表联接时才用on的,所以在一个表的时候,就剩下where跟having比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where可以使用rushmore技术,而having就不能,在速度上后者要慢如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,根据上篇写的工作流程,where的作用时间是在计算之前就完成的,而having就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。在多表联接查询时,on比where更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where进行过滤,然后再计算,计算完后再由having进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里
(12) 减少对表的查询:
在含有子查询的SQL语句中,要特别注意减少对表的查询.例子:
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
(13) 通过内部函数提高SQL效率.:
复杂的SQL往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的
(14) 使用表的别名(Alias):
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.
java 流
//管子一层套一层具有更特殊的功能
Java语言的输入输出功能是十分强大而灵活的,对于数据的输入和输出操作以“流”(stream)的方式进行。J2SDK提供了各种各样的“流”类,用以获取不同种类的数据,定义在包java.io中。程序中通过标准的方法输入或输出数据。
Java中的流可以从不同的角度进行分类:
按照流的方向不同:分为输入流和输出流。
按照处理数据单位的不同:分为字节流(8位)和字符流(16位)。
按照功能不同:分为节点流和处理流。
节点流:是可以从一个特定的数据源(节点)读写数据的流(例如文件,内存)。就像是一条单一的管子接到水龙头上开始放水。
处理流:是“连接”在已经存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。就像在已经接了一条管子(节点流)的基础上,又套上几个更粗,具有特殊功能的管子(处理流)对流出的水进一步的处理。
queue队列 和 堆栈stack
queue队列先进先出, 堆栈先进后出。
不用拼接sql,使用参数的好处
主要在于防止sql注入,一个变量在传递的时候只会传递一个值,有sql注入的情况会被检查出错误
拼接字符串不会检查输入是否合理,只要语法没问题就会被拼接
如:select * from aaaa where N=(拼接的内容) 这个语句如果符合SQL语法就会被执行
但如果人们输入select * from aaaa where N=('N' or 1=1) 时,无论N是否等于N,sql都会执行通过。这就是漏洞……
N=N or 1=1 无论任何时候 1都是=1的……
而执行参数传入时,只有一个合法的参数是可以被传入的……而(N=N or 1=1)这种情况是不被允许的……(不符合变量 N的类型)
大量数据的储存
http://www.codesky.net/article/201002/167897.html
1,分批多次提交commit
2,多次flash
3,线程sleep()
4,用存储过程,数据存储代替系统处理
threadlocal 互补多线程中共享变量的共享同步,具有threadlocal结构的变量可以以不同的副本在个线程单独使用
ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程” 。其实,ThreadLocal并不是一个 Thread,而是 Thread 的局部变量,也许把它命名为 ThreadLocalVariable更容易让人理解一些。当使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。
另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。
如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。
JDK 5 以后提供了泛型支持,ThreadLocal 被定义为支持泛型:
public class ThreadLocal<T> extends Object
T 为线程局部变量的类型。该类定义了 4 个方法:
1) protected T initialValue():返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。 该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。
2)public T get():返回此线程局部变量的当前线程副本中的值。如果变量没有用于当前线程的值,则先将其初始化为调用 initialValue() 方法返回的值。
3)public void set(T value):将此线程局部变量的当前线程副本中的值设置为指定值。大部分子类不需要重写此方法,它们只依靠 initialValue() 方法来设置线程局部变量的值。
4)public void remove():移除此线程局部变量当前线程的值。如果此线程局部变量随后被当前线程读取,且这期间当前线程没有设置其值,则将调用其 initialValue() 方法重新初始化其值。这将导致在当前线程多次调用 initialValue 方法。
下面是一个使用 ThreadLocal 的例子,每个线程产生自己独立的序列号。就是使用ThreadLocal存储每个线程独立的序列号复本,线程之间互不干扰。
package sync;
public class SequenceNumber {
// 定义匿名子类创建ThreadLocal的变量
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
// 覆盖初始化方法
public Integer initialValue() {
return 0;
}
};
// 下一个序列号
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
//私有的静态内部类在使用外部的非静态变量的时候要通过new对象的方式去用,不能直接用
private static class TestClient extends Thread {
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
// 线程产生序列号
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]");
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
SequenceNumber sn = new SequenceNumber();
// 三个线程产生各自的序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
}
程序的运行结果如下:
thread[Thread-1] sn[1]
thread[Thread-1] sn[2]
thread[Thread-1] sn[3]
thread[Thread-2] sn[1]
thread[Thread-2] sn[2]
thread[Thread-2] sn[3]
thread[Thread-0] sn[1] thread[Thread-0] sn[2]
thread[Thread-0] sn[3]
//单例模式的对象变量要私有的原因在于,只在内部赋值,外部要用这个变量只能通过get方法获取,防止其他地方篡改,构造函数私有的原因是为了总是一个对象,其他的地方不能new这个对象。
syschronized修饰的是静态的代码块,锁定的是调用这个方法的类,而不是对象。
//多线程的状态
当调用了start方法之后只是就绪状态,有cpu的时候才会运行
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
public class Test1 extends Thread{
public void run(){
System.out.println("Test:run()");
}
public void start(){
System.out.println("Test:start()");
}
public class Test2 implements Runnable{
public void run(){
System.out.println("Test2:run()");
}
public void start(){
System.out.println("Test2:start()");
}
}
public class TestThread {
public static void main(String[] args) {
//重写了父类的方法,所以只有子类起作用
Test1 t1 = new Test1();
//再包一层表示后续调用的如有重名覆盖的比如start,那么是调用线程里的,这里也重写了父类的方法,但是包了一层之后,用的是thread对象,此时的start是此对象的,不再有包了。
Thread t2 = new Thread(new Test2());
t1.start();//这个调用了那个类中的方法,而不是启动线程
t2.start();//这个调用了线程,这是为什么要包一层的原因
}
}
结果输出:
Test:start()
Test2:run()
直接调用run方法此时调用的不是线程,而是方法,这个线程还是主线程
请注意,当使用 runnable 接口时,您不能直接创建所需类的对象并运行它;必须从 Thread 类的一个实例内部运行它。许多程序员更喜欢 runnable 接口,因为Java多线程编程从 Thread 类继承会强加类层次。 包成thread
java中的数据类型,可分为两类:
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
他们之间的比较,应用双等号(==),比较的是他们的值。
2.复合数据类型(类)
当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址,但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
相关推荐
这套课程既可以作为从零基础开始学习的JAVA基础到高级学习教程,对于有JAVA基础的同学来说可以略过前面的JAVA基础章节,直接学习后续的JAVA高级部分课程。更可以灵活的作为章节技术,进行针对性的JAVA学习。还是要...
java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础课件java基础...
市面上目前流传的java基础视频教程都是讲一些最基础的java语法和相关API的应用,然而用人单位对初级程序员的要求越来越高,那些讲解java基础语法的视频教程已经无法满足大众的学习要求。本套视频教程录制完中国第一...
Java基础 java学习笔记 Java Java基础Markdown学习笔记,可转换成PDF、Word等格式
Java基础入门教程 第5章 Java基础类的应用(共42页).ppt Java基础入门教程 第6章 集合框架(共28页).ppt Java基础入门教程 第7章 Java中的异常处理(共26页).ppt Java基础入门教程 第8章 文件流的输入输出操作...
资源名称:Java基础加强系列视频课程资源目录:【】黑马程序员Java基础加强(01-10)【】黑马程序员Java基础加强(11-20)【】黑马程序员Java基础加强(21-30)【】黑马程序员Java基础加强(31-40)【】黑马程序员...
《Java 基础入门》课后习题答案 第 第 1 章 Java 开发入门 一、填空题 1、 Java EE、Java SE、Java ME 2、 JRE 3、 javac 4、 bin 5、 path、classpath 二、选择题 1、ABCD 2、C 3、D 4、B 5、B 三、简答题 1、 面向...
Java基础加强Java基础加强Java基础加强
Java基础思维导图涵盖大部分Java基础重点内容。适用于新手小白理解Java学习之路。
\Java基础类\Java基础类\Java基础类\Java基础类\Java基础类\Java基础类\Java基础类\Java基础类\Java基础类\Java基础类
完整版精品java课件 Java基础入门教程 Java程序设计 第1章 Java语言概述(共38页).ppt 完整版精品java课件 Java基础入门教程 Java程序设计 第2章 java语言基础(共31页).ppt 完整版精品java课件 Java基础入门教程 ...
java基础开发第一册希望对你们有帮助,其他还有很多资料
Java基础入门.pdf
java基础知识的培训ppt,对于java初学者来说可以有一些作用。
java基础知识大全(必看经典),里面包含了最基本的java基础知识,适合学习java的初学者和想要复习java基础的同学。
Java基础入门教程 第5章 Java基础类的应用(共42页).ppt Java基础入门教程 第6章 集合框架(共28页).ppt Java基础入门教程 第7章 Java中的异常处理(共26页).ppt Java基础入门教程 第8章 文件流的输入输出操作...
Java 基础入门,适合初学入门java的同学
java基础的案例分析和实例教学,适合新手及回顾查阅,对于夯实基础有好处
Java 基础
java基础知识,帮助初学者更快更好地掌握java。ppt内容具体易懂,希望对刚接触java的初学者有所帮助。