Java环境变量学习
每次拿到一台新的电脑总是从配Java的环境变量开始,从1.8开始就不用在自己手动配了,因为在安装jre的时候会自动在path下生成C:\Program Files (x86)\Common Files\Oracle\Java\javapath;(每个人路径可能不一样),对应路径下有java的可执行文件,对此了解一下环境变量、Java的三个环境变量的含义。
环境变量(百度百科):是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。例如Windows和DOS操作系统中的path环境变量,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中指定的路径去找。用户通过设置环境变量,来更好的运行进程。
也就是说,当我们win+r输入cmd弹出命令窗口,其实是运行了cmd.exe可执行文件,他会先从当前目录下找,找不到再去环境变量里找,都找不到的话就报错,所以当多个程序运行用到同一个文件时,可设在环境变量里。
JAVA_HOME:java的安装目录,方便后面引用
C:\Program Files\Java\jdk1.8.0_221
path:把java的bin目录输进来就可以在任意路径下执行java/javac命令了
%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin
CLASS_PATH:java执行所需要的的类包,.;表示当前路径,如果不用Swing,可以不加dt.jar。 tools.jar里面是最基本的工具类,不能不加
.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
参考文章:环境变量必须配吗?
volatile
- 修饰变量,每次都重新读取该变量的值,而不是读取寄存器中的备份,AtomicInteger里的value值就是用volatile修饰
- 不能保证线程原子性(cpu被抢占,线程被切分),原子性可通过synchronized关键字实现
比如 count++分为三步
int tmp = count;tmp = count + 1;count = tmp;
- 因为volatile不能保证原子性,当两个cpu同时执行时,可能会出现丢失一个count++的情况,所以需要加synchronized保证原子性
- volatile满足happens before,单例对象在声明时加上volatile可以避免指令重排时出现只有地址的空对象,会在对象实例化后再对对象赋值。
private static volatile Singleton instance = null;
public class Singleton {
private static volatile Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if(instance ==null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
instance = new Singleton()分为三步
分配对象空间;初始化对象;设置instance指向刚刚分配的地址。
String
- replaceAll(reg,replacement) 将所有匹配reg字符的替换为replacement,常用于日志信息替换,比如自定义错误码文件message-logger.properties,文件中定义luneo-cloud=数据转换异常,{0},使用val.replaceAll("\{"+0+"\}",str);str通过Property读取进来。
- StringBuffer 线程安全,所有公开方法都用synchronized修饰;适用于多线程场景,但性能比StringBuilder低;StringBuffer 每次获取 toString 是使用缓存区的 toStringCache 值来构造一个字符串。而 StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串。
private transient char[] toStringCache;
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
- StringBuilder线程不安全,适用于单线程场景,性能较StringBuffer高。
transient
使用transient修饰的变量不参与序列化过程
Property
- 读取配置文件中的信息作为异常日志输出:先通过
PathMatchingResourcePatternResolver获取Resource查找器,再获取指定路径下的文件流,使用PropertiesLoaderUtils将resourcr转换为Property,再使用replaceAll将占位符替换为传入参数,最后使用StringBuffer将异常信息拼接返回
equals和==
==,对基本数据类型比较的是值,对引用类型比较的是地址
equals,只能比较引用类型,用于判断两个字符串的长度和内容是否相等,区分大小写。没重写之前本质上是双等号,只能比较引用类型的地址,没多大意义
native
本地方法,java调用非java实现的方法。
Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。
ArrayList
add(int index,E element)在数组为空时不能使用,因为size为0,而且必须按顺序寸值,指定位置为空时不能使用
//将element从index开始复制到index+1之后到结尾
System.arrayCopy(elementData,index,elementData,index+1,size-index);
elementData[index]=element;
size++;
//相当于插入操作,index后的数据往后移
indexOf(Object o)中,判断对象相等,分对象为null和非null,为null用==判断,非null用equals,且有必要区分,因为当对象为null时,用equals判断会报空指针异常- 添加操作思路,先扩容,将index后的元素后移,再将待添加的元素复制进来,使用
System.arrayCopy,修改size
add(int index,Element e) - 删除操作思路,先将index+指定长度后的元素往前移,然后将index后的元素置为null,再修改size
remove(int index) elementData.length取得是数组的容量retainAll(Collection<?> c)用于从ArrayList中移除未包含在指定集合中的所有元素。list1.retainAll(list2)表示把list1中和list2不一样的去掉,求交集list1.removeAll(list2)表示把list1中与list2一样的移除,去掉交集batchRemove(Collection<?> c,boolean completment)思路解析,当complement为false时,将list1中不一样的值从0开始给list1重新赋值,element[w++]=element[r],再将w之后的元素置为null,给modCount,size重新赋值,complement为true同理- 疑问?
checkModification()的作用是啥?modCount和expectedModCount??
左加加和右加加
- 左加加,表示先进行运算,再自增
- 右加加,表示先自增,再进行运算
ArrayList在add(E e)时,elementData[size++]=e;
在remove(int index)时,elementData[--size]=null;
size比下标大1
泛型
- 泛型的作用是为了减少强制类型转换的繁琐操作
- 泛型通配符的作用是为了保证类型安全
<? extends E>用来限制元素类型的上限E,即只能是E或E的子类,如果集合元素类型为E的父类则编译报错;<? extends E>写操作,由于集合类型是不确定的,为了类型安全,编译器阻止添加元素<? extends E>读操作,由于集合类型一定是E的子类或E本身,所以允许读<?>是<? extends Object>的简写<? super E>用来限制元素的类型下限,即只能是E或E的父类;<? super E>写操作,如果C-D-E组成父子,C可往D中写,但E不可往D中写<? super E>读操作,因为Object是任何类的父类,所以可读,需要强制类型转换- 如果你需要一个提供E类型元素的集合,使用泛型通配符<? extends E>,适用于频繁往外读取内容
- 如果你需要一个只能装入E类型元素的集合,使用泛型通配符<? super E>,适用于经常往里插入数据的
- 既要存储又要读取,就不要使用泛型通配符。
修饰符使用场景
- public适用于包之间业务逻辑的调用
- protected适用于同包下类之间调用且需要继承重写扩展的方法
- default适用于同包下类之间调用,不可继承
- private类内部调用
iterator迭代器
- 为了遍历无序集合设计,比如Set,无法用for循环对Set进行遍历(可用增强for,本质是迭代器)
hasNext()判断size是否与游标相等,判断是否遍历完了next()返回游标当前位置的元素,并且游标位置+1remove()删除游标左边的元素,只能在next()执行后执行一次previous(),游标前移,取游标位置处的元素- 实现了Iterable接口的集合都可以使用迭代器来遍历。使用迭代器遍历元素时,除了获取元素之外,只能做remove操作。
- 增强for循环,遍历时只能获取元素,不能添加,修改和删除
set(E e)只有在next()调用之后lastRet改变了才能使用set()
内部类
- 在一个类内部的类,可以是private或protected(非内部类不允许)
- 编译后为文件名为外部类$内部类.class
- 应用场景:①当类与接口(或接口与接口)发生方法命名冲突时,可以使用内部类来实现。用接口+内部类才能实现真正的多继承。
- 内部类声明为静态的,只能访问外部类的静态成员变量,非静态可以访问外部类的所有成员变量
- 成员内部类:作为外部类的一个成员变量存在,不能定义静态变量,可访问外部类的所有成员
Outer.this.j内部类取外部类(当存在同名属性时),只取j表示取的内部类,也可取外部类的私有属性
Outer outer = new Outer();
Inner inner = outer.new Inner();
System.out.println(inner.k);(k为内部类的私有属性)
- 局部内部类:在方法内定义的内部类,作为类的局部变量,不能用private,public,protected修饰,可访问外部类的成员变量和局部变量(方法内的)和静态变量,访问局部内部类必须先有外部类对象,对象调用方法,在方法中才能调用其局部内部类
- 静态内部类:定义在类中方法外,可以用private,protected,public修饰,可以定义静态或非静态成员,只能访问外部类的静态对象??
- 匿名内部类,特殊的局部内部类,唯一一种无构造方法的类,编译后文件名为Outer$1.class;new A(){},类A不是内部类
- 总结:①非静态内部类,内部隐含有外部类的指针this,因此可以访问外类的所有成员;外部类访问内部类,先要获得内部类对象,且取决于内部类对象的访问修饰符;不能包含非静态成员
②静态内部类,不包含外部类的指针this;在外部类装载时初始化;外部类通过类名.属性访问内部类静态成员,通过对象.属性访问非静态成员;静态内部类能包含静态成员或非静态成员;静态内部类只能访问外部类的静态成员;
16万+

被折叠的 条评论
为什么被折叠?



