FileDescriptor思想
FileDescriptor(FD)来自POSIX Operating System,FileDescriptor是表示文件访问的抽象标识。
In POSIX, a file descriptor is aninteger, specifically of the C type int. There are three standard POSIX file descriptors, corresponding to the threestandard streams, which presumably every process (save perhaps adaemon) should expect to have:
Integer value | Name |
0 | Standard input (stdin) |
1 | Standard output (stdout) |
2 | Standard error (stderr) |
示例
//输出
FileOutputStream fos = new FileOutputStream(FileDescriptor.err);
try {
fos.write(new String("I'm a keyboard operator.").getBytes());
} catch (IOException e) {
e.printStackTrace();
}
//输入
byte[] buff = new byte[1024];
int flag = -1;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(FileDescriptor.in));
try {
while ((flag = bis.read(buff)) != -1) {
System.out.println(new String(buff, 0, flag));
}
} catch (IOException e) {
e.printStackTrace();
}
Java随机数
两种处理方式
1、Math.random();
2、Random randInst = new Random();
Math.random();
这种方式生成0-1之间的随机数,可通过计算公式来完成特定需求的随机数生成;
示例:
生成0-5之间的随机数
int randVariable = (int) Math.random() * 5;
Jar包的信息
J2SE提供有相关的API用来对jar文件进行处理,可以通过创建相关api实例进行处理(如:java.util.jar.JarFile)。
包访问权限
| private | package | protected | public |
类自身/内部类 | √ | √ | √ | √ |
同级包中的类 |
| √ | √ | √ |
同级包中的子类 |
| √ | √ | √ |
任意非同级包中的子类 |
|
| √ | √ |
下一级包中的子类 |
|
| √ | √ |
下级包中的类/其它类 |
|
|
| √ |
final关键字
final修饰变量
使用final修饰的变量内存地址不允许更改,但变量如果是复合类型时则变量内存地址所嵌套的内存地址是可以改变的,如下表述:
public static final UserEntity userEntity = new UserEntity();
public void doWork() {
userEntity.userName = "WangYanCheng";
//变量内存地址是不可以更改的
//userEntity = new UserEntity();
}
空白final
一个类中的final域就可以做到根据对象而有所不同,却又保持其恒定不变的特性,必须保证空白final在使用前被初始化,有如下表述:
public class BlankFinal{
public static final UserEntity userEntity;
public BlankFinal() {
userEntity = new UserEntity();
}
}
final方法
使用final方法的两个原因:
1、把方法锁定,以防止任何继承类修改它的含义。这是出于设计上的考虑:想要确保在继承中使方法行为保持不变,并且不会被覆盖。
2、第二个原因是效率,不过随着JVM的改良这块已经不建议使用。
类中所有的private修饰的方法都隐式的指定为final的,但最好不好直接对private方法增加final修饰这样容易引起混淆。private修改的方法是不会被覆盖的,如果其子类创建了一个与父类相同的private修饰的方法也仅是子类新添加的方法而不是覆盖。
final类
使用final修饰class是计划该类不要被继承、今后也不会有任何的扩展或设计上的变动或者出于安全考虑不希望它有子类。
static与静态域
在执行构造方法之前类的成员变量都会被初始化成0或null,这种方式是简单的内存清零而成的。
类的成员变量有静态成员变量与非静态成员变量(实例成员变量)。
实例成员变量:作用域在类实例,各个对象的成员变量不共享。
静态成员变量:作用域在类级别,可以不创建实例化对象而使用,通过类名.变量名的方式,各类的对象实例共享静态变量,所以静态成员变量只会初始化一次。
类的初始化顺序
- 初始化类的静态变量,执行类的静态域。
- 初始化类实例变量(在实例变量赋初始值的情况)执行类的构造器。
- 在有继承体系结构场景中,类变量的初始化顺序由上至下(也就是由基类中的静态变量静态域到子类中的静态变量静态域)。
- static变量或static作用域只会执行一次。
null的equals
public static void main(String[] args) {
String abc = new String();
//永远不等
if (abc.equals(null)) {
}
//永远不等
if (null instanceof Object) {
}
}
Map或其它集合的初始化
mainMapArr = new ArrayList(){{
add(new HashMap(){{put("ctNo", "WangYanCheng");}});
add(new HashMap(){{put("ctNo", Math.random());}});
add(new HashMap(){{put("ctNo", new int[10]);}});
add(new HashMap(){{put("ctNo", "正常情况 下的字符串");}});
}};
subMapArr = new ArrayList(){{
add(new HashMap(){{put("depNo", 001D);}});
add(new HashMap(){{put("depNo", String.valueOf(Math.random()));}});
add(new HashMap(){{put("depNo", null);}});
add(new HashMap(){{put("depNo", "字符串");}});
}};
枚举类型体、相、用
枚举类型也就是声明为enum的对象,它的作用就是定义和规范软件系统常量、以及常量的值。
语法
public enum TaskType {
/** 表对象 */
TABLE_OBJ(1),
/** 表字段对象 */
TABLE_FIELDOBJ(2),
/** 视图对象 */
VIEW_OBJ(3);
private int taskType;
/**
* Constructor
* @param taskType taskType
*/
TaskType(int taskType) {
this.taskType = taskType;
}
}
注意
- 枚举类型的定义在声明类的上面
- 类型及类似构造函数放到了下面
- 这些语法规则是必须的
使用Oracle的DBA权限进行JDBC的连接
Properties prop = new Properties();
prop.setProperty("internal_logon',"sysdba");
OracleDataSource odsInst = new OracleDataSource();
odsInst.setConnectionProperties(prop);
odsInst.setURL("jdbc:oracle:thin:@localhost:1521/orcl");
Connection conn = odsInst.getConnection();
SQL Server的JDBC
http://msdn.microsoft.com/zh-cn/data/aa937724.aspx
JDBC中的日期
两个类:
- java.util.Date
- java.sql.Date
- 两个类是有继承关系的
为什么要有java.sql.Date?
- 因为java.sql.Date被用在与数据库场景而java.util.Date被用在所有场景。
两个类可以互换么?如何实现?
- 使用java.sql.Date.getTime()可以互换成java.util.Date
- java.util.Date.getTime()也可以互换成java.sql.Date
传值还是传引用
在C/C++中给方法参数传递对象引用是可以直接更改对象内存地址的,而在Java中情况并不是这样子。
对于基本类型byte、short、char、float、double都会是传值也就是传该变量的一个副本,在方法内对参数值的改变不会影响到外部变量。
对于String类型的变量参数传递,首先String是对象但String是public class final String所以传递String是不会改变的,同样性质的还有StringBuffer\StringBuilder,但针对它们内存块地址所持有的地址是可以改变的。
这种性质的表述如下:
StringBuffer sbuf = new StringBuffer();
public void doWork(StringBuffer sbud) {
//更改有效
sbud.append("New String");
//更改无效
sbud = new StringBuffer();
sbud.append(".");
}
同样Java的传值与传引用就此区分开了,基本类型与复合类型(对象)都是传值,都是传递的副本。
但是复合类型地址副本所指向的内存地址是可以改变的,由此引申出某对象的属性被更改了。
有如下代码表述:
class User {
String userCode;
}
public void changeUserCode(User user) {
user.userCode = "WangYanCheng";
}
当然这种性质在Java相关Collection中也会是这种表述。
缓存要考虑的问题
- 过于依赖语言的序列化机制
- 缓存大对象
- 在堆选择大小相符的块很费时
- 内存碎片,垃圾回收压缩堆的机制
- 线程间数据的共享
- Race Condition问题
- 同步锁竞争
- 数据会被立刻缓存
- 绝对过期与相对过期时间
- 自身应用压力很大造成缓存的数据在访问时已经超时
- 缓存大量的数据而只读取其中某一部分
- 缓存大量具有图结构的数据而导致内存浪费
- 缓存应用程序的配置信息
- 不同的键指向相同的缓存项
- 及时更新或删除缓存中已失效或过期的数据
只读集合
只读集合Collections.emptyType()的意义在于查询读取数据但永远不会写入数据的场景
我想在初始化的时候把某个集合类型的成员初始成只读集合,但后期逻辑运行时我还要写数据 | × |
我想查询一些数据,当数据不存在时我也不想在客户端程序验证结果集是不是NULL | √ |
HTTPS文件下载问题
场景
https模式浏览器下载文件出错,这块网友讨论是IE浏览器的Bug需要开启缓存权限
要点/解决
考虑在response响应头中添加声明开启缓存权限的标记,此问题主要是浏览器对HTTP协议的处理
1.考虑添加开启缓存权限
2.考虑修改客户端IE安全配置
3.考虑修改客户端注册表
4.删除no-cache标头
参考资料
1.http://support.microsoft.com/kb/316431
2.扩展阅读RFC2616
POI#HSSF#单元格的宽度
场景/示例
单元格的宽度问题,可不再是简单的setColumnName(colIndex,20);它就是20个像素的宽,读API可知道这个值的基准是1/256,最大值是(256*256)-1。
通过测试发现映射到Excel的列宽度只是近似值,并不十分精确,如20*256映射到Excel就变成19.27
JAVA#IO#临时文件的删除
场景
业务逻辑处理过程中创建了多个昨时文件用来辅助业务操作,业务逻辑处理完成后要想着清理这些临时文件,有哪些办法呢?
方案
- 等待JVM退出时删除File#deleteOnExit();但考虑到7*24小时运行的系统是不允许宕机的。。。
- 在逻辑退出时手工进行删除,经测试发现当该文件正在被其它线程使用时是不允许顺利的删除掉的,这需要系统提供统一管理临时文件的模块(把要删除的文件记录下来在某个时间点统一处理)。
Java的异常
场景
try# catch#finally语句处理异常时catch是分优先级的,如下:
public class ExceptionTest {
public void doWork() {
try {
throw new RuntimeException();
} catch (RuntimeException re) {
System.out.println("1");
} catch (Throwable t) {
System.out.println("2");
} finally {
System.out.println("3");
}
}
public static void main(String[] args) {
new ExceptionTest().doWork();
}
}
总结
异常是区分范围的,在被RuntimeException处理之后是不会被Throwable继续处理,注意finally和catch的执行顺序,catch==>finally,程序最终执行结果:1\r\n3
传递声明了final的参数
/**
* 注意参数声明了final
* <p>1、标识该函数不能修改传递参数实例的内存地址
* <p>2、但可以修改该参数内部变量引用的内存地址
* @param innerClass
*/
public void doWork(final InnerClass innerClass) {
innerClass.setFinalIntValue(5);
innerClass.setFinalObjValue(new Object());
}
Java#ThreadLocal理解
每个线程都有独立的线程存储区,这块区域中有一个类似Map#Key-Value的数据结构,这个结构的Key就是ThreadLocal实例,Value则是通过ThreadLocal#set(T t)放置的内容。
注意,利用ThreadLocal只能存储一个变量至Thread#ThreadLocalMap,因为传递ThreadLocalMap的Key是ThreadLocal,如果要通过一个ThreadLocal管理多个变量,就应该构造一个Map的对象,然后该Map对象通过ThreadLocal#set/get取得,该Map对象则可以存储多个变量和普通Map一致。
ThreadLocal#set/get处理的流程
1、set流程
1.1、取当前线程实例
1.2、从当前线程实例取ThreadLocalMap变量
1.3、如果ThreadLocalMap为空,则创建ThreadLocalMap,Key为当前ThreadLocal实例,Value为传递的参数值,ThreadLocalMap创建完成后绑定到当前线程的ThreadLocalMap变量。
1.4、如果ThreadLocalMap不为空,直接存储值,原来的值将会被覆盖
2、get流程
2.1、取当前线程实例
2.2、取当前线程ThreadLocalMap变量
2.3、如果ThreadLocalMap为空则进入线程ThreadLocalMap变量初始化流程。
2.3.1、取初始值java.lang.ThreadLocal.initialValue()
2.3.2、取当前线程ThreadLocalMap变量
2.3.3、如果ThreadLocalMap不为空,直接存储值,原来的值将会被覆盖
2.3.4、如果ThreadLocalMap为空,则创建ThreadLocalMap,Key为当前ThreadLocal实例,Value为取到的初始值
2.4、如果ThreadLocalMap不为空,取依据ThreadLocal实例取ThreadLocalMap#Entry,如果ThreadLocalMap#Entry不为空,则返回ThreadLocalMap#Entry#value。
Java#字符格式化
提供三种基础字符格式化(日期、数字、信息)
结构图