Java

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()返回游标当前位置的元素,并且游标位置+1
  • remove()删除游标左边的元素,只能在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;在外部类装载时初始化;外部类通过类名.属性访问内部类静态成员,通过对象.属性访问非静态成员;静态内部类能包含静态成员或非静态成员;静态内部类只能访问外部类的静态成员;
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值