Java开发基础

Java开发基础


Integer

  • 自动装箱和拆箱。
Integer i = 100;
// 编译后
Integer i = Integer.valueOf(100);

// JDK源码:
public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  • 缓存。
// 缓存
Integer i = 100;
Integer j = 100;
System.out.println(i == j); // 执行结果?

// JDK源码
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // 初始化cache。
    }

    private IntegerCache() {}
}
  • Integer非线程安全,例如i + +,i - -,多线程访问无法保证一致性。
Integer i = new Integer(0);

public void test() {
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int j = 0; j < 10; j++) {
                i++;
                System.out.println(i);
                try {
                    Thread.sleep(10 * j);
                } catch (Exception e) {
                }
            }
        }
    });
    t1.start();

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int j = 0; j < 10; j++) {
                i--;
                System.out.println(i);
                try {
                    Thread.sleep(10 * j);
                } catch (Exception e) {
                }
            }
        }
    });
    t2.start();
}
  • java.util.concurrent.atomic.AtomicInteger:一个提供原子操作的Integer的类。
  • 内部通过volatile实现多线程可见性。使用原生Unsafe类实现同步修改。unsafe.compareAndSwapInt:比较obj的offset处内存位置中的值和期望的值,如果相同则更新,并返回TRUE。
// AtomicInteger
public final int get(); // 获取当前的值
public final int getAndSet(int newValue); // 取当前的值,并设置新的值
public final int getAndIncrement(); // 获取当前的值,并自增
public final int getAndDecrement(); // 获取当前的值,并自减
public final int getAndAdd(int delta); // 获取当前的值,并加上预期的值

AtomicInteger i = new AtomicInteger(0);
public void test() {
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int j = 0; j < 10; j++) {
                i.getAndIncrement();
                System.out.println(i);
                try {
                    Thread.sleep(10 * j);
                } catch (Exception e) {
                }
            }
        }
    });
    t1.start();

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int j = 0; j < 10; j++) {
                i.getAndDecrement();
                System.out.println(i);
                try {
                    Thread.sleep(10 * j);
                } catch (Exception e) {
                }
            }
        }
    });
    t2.start();
}
  • 当我们使用VO或Form封装前端传入的参数时,数值型参数我们是定义成int还是Integer?

String

  • 一个字符串常量只有一个拷贝,不可变性,内容存放常量池。
String str0 = "123";
String str1 = "123";
String str2 = "12" + "3"; // 编译后"123"

static final String str = "3";
String str3 = "12" + str; // 编译后"123"

System.out.println(str0 == str1); //结果?
System.out.println(str1 == str2); //结果?

String str3 = new String("123");
String str4 = new String("123");
System.out.println(str3 == str4); //结果?
  • 常用方法
public int compareToIgnoreCase(String str); // 比较(忽略大小写)
public boolean startsWith(String prefix); // 传入的是
public boolean matches(String regex); // 正则匹配。
public static String format(String format, Object... args); // 格式化。
public String[] split(String regex); // 注意是正则表达式。
  • StringBuffer、StringBuilder

    StringBuilder线程不安全,StringBuffer线程安全(synchronized)。

    定义常量时,使用String。速度快。

  • StringUtils(Commons, Spring)
>>> org.apache.commons.lang.StringUtils
public static boolean isEmpty(String str); // 判断是否为空串。
public static boolean isBlank(String str); // 判断是否为空白串。
public static boolean contains(String str, String searchStr); // 包含

public static String join(Object[] array, String separator); // 字符串拼接。
StringUtils.join(["a", "b", "c"], "-") = "a-b-c"

public static String rightPad(String str, int size, char padChar); // 右边补齐
StringUtils.rightPad("bat", 5, ‘z‘)  = "batzz"

public static boolean isAlpha(String str); // 是否全字母。
public static boolean isAlphanumeric(String str); // 是否只包含字母和数字。

public static String abbreviate(String str, int maxWidth); // 过长省略。
StringUtils.abbreviate("abcdefg", 6) = "abc..."

>>> org.springframework.util.StringUtils
public static String getFilename(String path); // 获取文件名,不包含路径。
public static String getFilenameExtension(String path); // 获取文件后缀名。

>>> org.apache.commons.lang.builder.ToStringBuilder
public static String reflectionToString(Object object, ToStringStyle style); // 打印对象属性。

Array

  • 数组初始化
  • 数组相关常用类
// 初始化
String[] arr1 = new String[6];
String[] arr2 = {"a", "b", "c", "d", "e"};
String[] arr3 = new String[]{"a", "b", "c", "d", "e"};

>>> java.util.Arrays
public static void sort(Object[] a); // 排序
public static int binarySearch(Object[] a, Object key); // 二分法查找,前提数组是有序的。
public static <T> List<T> asList(T... a); // 转成List。
public static String toString(Object[] a); // 拼装元素,可用作打印。

>>> org.apache.commons.lang.ArrayUtils
public static void reverse(Object array[]); // 元素翻转。
public static Object[] addAll(Object array1[], Object array2[]); // 两个数组拼接。
public static boolean contains(Object array[], Object objectToFind); // 包含某个元素。
public static int indexOf(Object array[], Object objectToFind); // 查找元素位置。
public static Object[] remove(Object array[], int index); // 移除第几个元素。

List

  • 面向接口编程:List
// 调用方不需要知道List的实现。
List<Object> lst = new ArrayList<Object>();
  • ArrayList增长机制,源码。
  • 特性:插入慢(当数据到一定量时),遍历速度快。
// JDK源码
private transient Object[] elementData; // 内部维护一个数组。

public ArrayList() { // 初始化长度10
    this(10);
}

public ArrayList(int initialCapacity) { // 指定初始化大小。
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
    this.elementData = new Object[initialCapacity];
}

public boolean add(E e) {
    ensureCapacity(size + 1); // 扩展长度。
    elementData[size++] = e;
    return true;
}

public void ensureCapacity(int minCapacity) { // 扩展长度。
    modCount++;
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object oldData[] = elementData;
        int newCapacity = (oldCapacity * 3)/2 + 1; // 按1.5倍增长。
        if (newCapacity < minCapacity)
            newCapacity = minCapacity;
        elementData = Arrays.copyOf(elementData, newCapacity); // 数组拷贝,耗性能。
    }
}

public E get(int index) { // 直接通过下标返回数组元素。
    RangeCheck(index);
    return (E) elementData[index];
}
  • LinkedList源码。
  • 特性:插入速度快,遍历速度慢。

// JDK源码
private transient Entry<E> header = new Entry<E>(null, null, null); // 起始节点。

private static class Entry<E> { // 每个节点元素。
    E element;
    Entry<E> next;
    Entry<E> previous;
    ...
}

public boolean add(E e) { // 增加元素。
    addBefore(e, header);
    return true;
}

private Entry<E> addBefore(E e, Entry<E> entry) { // 新增节点,修改引用即可。
    Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
    newEntry.previous.next = newEntry;
    newEntry.next.previous = newEntry;
    size++;
    modCount++;
    return newEntry;
}

public E get(int index) { // 查找元素。
    return entry(index).element;
}

private Entry<E> entry(int index) { // 依次遍历,性能差。
    if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
    Entry<E> e = header;
    if (index < (size >> 1)) {
        for (int i = 0; i <= index; i++)
            e = e.next;
    } else {
        for (int i = size; i > index; i--)
            e = e.previous;
    }
    return e;
}
  • 两者比较:链表插入数据速度快的说法是相对的,在数据量很小的时候,ArrayList的插入速度不仅不比LinkedList慢,而且还快很多。只有当数据量达到一定量,这个特性才会体现出来,使用时根据场景选择。
  • 工具类
>>> java.util.Collections
public static <T extends Comparable<? super T>> void sort(List<T> list); // 排序。
public static <T> void sort(List<T> list, Comparator<? super T> c);
public static <T> boolean addAll(Collection<? super T> c, T... elements); // 添加多个元素。

>>> org.apache.commons.collections.CollectionUtils
public static boolean isEmpty(Collection coll); // 是否为空。
public static Collection removeAll(Collection collection, Collection remove); // 移除。
public static Collection union(Collection a, Collection b); // 并集。
public static Collection intersection(Collection a, Collection b); // 交集。
public static Collection disjunction(Collection a, Collection b); // 交集的补集。
public static Collection subtract(Collection a, Collection b); // 集合相减。

>>> com.google.common.collect.Lists
List<String> lst = new ArrayList<String>(); // 这样初始化代码多,麻烦。
lst.add("a");
lst.add("b");
lst.add("c");

Lists.newArrayList("a", "b", "c"); // 简单明了。
Lists.newArrayListWithCapacity(3);
Lists.newLinkedList();
  • CopyOnWriteArrayList。可并发的ArrayList,读写分离。
List<String> lst = new ArrayList<String>();
lst.add("a");
lst.add("b");
lst.add("c");

for (Iterator<String> itor = lst.iterator(); itor.hasNext(); ) { // 有问题,ConcurrentModificationException
    if ("b".equals(itor.next())) {
        lst.remove(itor.next());
    }
}

for (Iterator<String> itor = lst.iterator(); itor.hasNext(); ) { // 使用Iterator.remove
    if ("a".equals(itor.next())) {
//      lst.remove(itor.next());
        itor.remove();
    }
}

List<String> lst = new CopyOnWriteArrayList<String>(); // 定义CopyOnWriteArrayList

Map

  • Map作为最基本的数据结果,在代码中出现频率非常大。Java JDK、C++ STL都对其有很好的支持。
  • HashMap、Hashtable内部维护了一个Entry数组。不同的是Hashtable对操作的方法都使用了synchronized确保线程安全。
  • HashTable中hash数组默认大小是11,增加的方式是 old * 2 + 1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
  • 加载因子:Hsah表中元素的填满的程度。加载因子越大,填满的元素越多,空间利用率高,Hash冲突的机会大。加载因子越小,填满的元素越少,冲突的机会减小,空间浪费多了。

    冲突的机会越大,则查找的成本越高。反之,查找的成本越小。

JDK源码:
/**
 * Constructs an empty <tt>HashMap</tt> with the default initial capacity
 * (16) and the default load factor (0.75).
 */
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    table = new Entry[DEFAULT_INITIAL_CAPACITY];
    init();
}

public V put(K key, V value) { // 添加
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode()); // 计算Hash对应的表索引。
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { // 替换相同的Key元素。
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i); //
    return null;
}

void addEntry(int hash, K key, V value, int bucketIndex) { // 添加新元素到链表头。
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    if (size++ >= threshold)
        resize(2 * table.length); // 扩容,会重新调整Hash数组,代价较高。
}

public V get(Object key) { // 查找。
    if (key == null)
        return getForNullKey();
    int hash = hash(key.hashCode()); // 计算Hash对应的表索引。
    for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}

Map<String, String> map = new HashMap<String, String>(4); // 这样写会扩容吗?
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
map.put("4", "4");
Map<String, String> map = new HashMap<String, String>(4, 1);
  • TreeMap内部通过红黑树保证取出来的是排序后的键值对。插入、删除需要维护平衡会牺牲一些效率。但如果要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。Comparable, Comparator. TreeMap详解
  • TreeSet内部通过TreeMap实现。TreeSet元素实现Comparable接口或自定义比较器。
  • HashMap效率高线程不安全,Hashtable线程安全但效率不高。ConcurrentHashMap折中办法。

Guava增强的集合

  • Multiset:可重复的Set。HashMultiset,内部HashMap实现。
List<Integer> lst = Lists.newArrayList(1, 2, 3, 4, 2, 3);

// 一般写法
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer i : lst) {
    Integer count = map.get(i);
    if (count == null) {
        map.put(i, 1);
    } else {
        map.put(i, count + 1);
    }
}
System.out.println(map.get(2)); // 结果:2

// Guava写法
Multiset<Integer> set = HashMultiset.create();
set.addAll(lst);
int count = set.count(2); // 结果:2
System.out.println(Arrays.toString(set.toArray())); // 结果为排序后的:[1, 2, 2, 3, 3, 4]
  • BiMap:一个双向映射的Map,强制Value唯一性。
BiMap<String, String> map = HashBiMap.create();
map.put("M", "1");
map.put("F", "2");
map.put("F", "1"); // 报错:value already present.
map.forcePut("F", "3"); // 忽略校验Put
System.out.println(map.get("F")); // 3
System.out.println(map.inverse().get("1")); // M
  • Multimap:一个Key对应多个Value,比Map
Map<String, List<Integer>> map = new HashMap<String, List<Integer>>(); // 一般写法。

Multimap<String, Integer> multimap = ArrayListMultimap.create(); // Guava写法。
for (int i = 0; i < 10; i++) {
    multimap.put((i % 2 == 0) ? "m" : "n", i);
}
System.out.println("size: " + multimap.size()); // size: 10
System.out.println("keys: " + multimap.keys()); // keys: [n x 5, m x 5]
System.out.println(multimap.get("m").toString()); // [0, 2, 4, 6, 8]
System.out.println(multimap.get("n").toString()); // [1, 3, 5, 7, 9]
System.out.println(multimap.containsValue(10)); // FALSE,是否存在指定的Value

反射

  • Java反射机制主要提供了以下功能:在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
class User {
    private String name;
    public Integer age;
    private String getName() {
        return name;
    }
    public Integer getAge() {
        return age;
    }
    public static void Test() {
        System.out.println("Test");
    }
}

Class clazz = User.class;
User user = (User)clazz.newInstance();
user.age = 10;

clazz.getSimpleName(); // User
clazz.getName(); // 包名+User
clazz.getPackage();

Field[] fields = clazz.getDeclaredFields(); // 声明的所有属性。[name, age]
Field[] fields = clazz.getFields(); // 可访问的。[age]

Object value = clazz.getField("age").get(user); // 10

Method[] methods = clazz.getDeclaredMethods(); // 声明的所有方法。[getAge, getName]
Method[] methods = clazz.getMethods(); // 可访问的。[getAge, equals, toString, hashCode...]

Object result = clazz.getMethod("getAge").invoke(user); // 10
clazz.getMethod("Test").invoke(null); // 调用静态方法

PropertyDescriptor pd = new PropertyDescriptor("name", clazz);
pd.getReadMethod().getName();

Bean属性复制

  • Commons BeanUtils PropertyUtils, Spring BeanUtils
  • Commons的BeanUtils.copyProperties()会对类型转换,如:Integer默认0。Spring的BeanUtils.copyProperties()不会。
  • Commons的PropertyUtils.copyProperties()对属性的类型强校验。
  • 类型转换:org.apache.commons.beanutils.converters
public class User1 {
    private Integer age;
    private Integer name;

    // getter setter ...
}

public class User2 {
    private Integer age;
    private String name;

    // getter setter ...
}

User1 u1 = new User1();
User2 u2 = new User2();
org.apache.commons.beanutils.BeanUtils.copyProperties(u2, u1); // u2.getAge() == 0
org.springframework.beans.BeanUtils.copyProperties(u1, u2); // u2.getAge() == null
org.apache.commons.beanutils.PropertyUtils.copyProperties(u2, u1); // u2.getAge() == null

User1 u1 = new User1();
u1.setName(123);
User2 u2 = new User2();
org.apache.commons.beanutils.BeanUtils.copyProperties(u2, u1); // u2.getName() == "123"
// Converting ‘Integer‘ value ‘123‘ to type ‘String‘
org.springframework.beans.BeanUtils.copyProperties(u1, u2); // u2.getName() == null
org.apache.commons.beanutils.PropertyUtils.copyProperties(u2, u1); // u2.getName() 报错
时间: 2024-10-19 16:48:47

Java开发基础的相关文章

Java开发基础——HttpClients与网络请求

Java开发中,经常会需要访问网络资源,一般都是使用http协议去进行访问.进行网络访问最简单的方式就是使用apache提供的HttpClients包.在该篇博客中,我会来实现使用HttpClients来进行GET请求和POST请求. 下面是使用GET请求访问"http://www.baidu.com"网站: public void get() { CloseableHttpClient httpclient = HttpClients.createDefault(); try { /

Java开发基础知识之规范篇——排版规范

网上流行的开发规范有很多,阿里巴巴.华为开发规范等等,当往往看得最舒服的才是最适合自己! 简单汇总了一下以往自己在项目开发中的编码风格规范: 1.程序块要采用缩进风格编写,缩进的空格数为4个. 2.分界符(如大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐.在函数体的开始.类和接口的定义.以及if.for.do.while.switch.case语句中的程序都要采用如上的缩进方式. 3.较长的语句.表达式或参数(>80字符)要分成多行书写,长表达式要在低优先级操作符处

Java开发基础知识之学习篇——Object类

JDK中所有类的基类——java.lang.Object 1.类构造器 创建java对象的途径之一,通过new关键字调用构造器完成对象的实例化,或通过构造器对象进行相应的初始化.在JDK的objec类源码中,系统会自动添加一个无参构造器. public object(){ Object obj = new Object(); //构造一个Object类的对象 } 2.registerNatives方法 静态代码块是一个类子啊初始化过程中必定会执行的内容,所以在类加载时会执行该方法,通过该方法来注

Java开发基础知识之学习篇——双亲委派机制

Java自带的类加载器: 启动类加载器(Bootstrap ClassLoader):这是由C++语言实现的一个加载器,是虚拟机的一部分,随虚拟机启动运行.负责将存放在/lib目录下面或者被-Xbootclasspath参数所指定的路径中的类. 扩展类加载器(Extension ClassLoader):负责加载/lib/ext目录中的,或者被java.ext.dir系统变量指定路径中的所有类库.如果把自己的jar包放到此位置,会首先用这个加载器加载. 应用程序类加载器(Application

Java开发基础知识之学习篇——String

String .StringBuffer 和StringBuilder 的区别是什么?从几个方面来解释. 1.可变性 String类中使用final关键字字符数组保存字符串,它的长度是不可变的. StringBuffer 和 StringBuilder 都继承自AbstractStringBuilder类,而在AbstractStringBuilder中也是使用字符数组保存字符串,但是没有用final关键字修饰,所以这两种对象都是可变的. 2.线程安全性 String中的对象是不可变的,就是常量

[Java 05 OO] (基础篇) 《Java开发实战经典》

p5OO 第五章 面向对象 (基础篇) Notes (1), Constructor / this / String   String str1 = "hello"; 解释 : 是把一个在堆内存空间的使用权给了 str1 对象.   String str2 = "hello"; str1 == str2 是 true   String 字符串的内容不可改变 (2), Java 常用的内存区域    1), 栈内存空间    2), 堆内存空间    3), 全局数据

JavaSE入门学习2:Java开发准备基础

一Java语言概述 Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言.Java 技术具有卓越的通用性.高效性.平台 移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算机.移动电话和互联网,同时拥有全球最大 的开发者专业社群. Java由四方面组成: (1)Java编程语言,即语法. (2)Java文件格式,即各种文件夹.文件的后缀. (3)Java虚拟机(JVM),即处理*.class文件的解释器. (4)Java应用程序接口(Java API). 二Java语言平台

零基础java培训靠谱吗?职场转行,零基础开始学Java开发靠谱吗?

学技术转行发展,是职场常见的提升方式,无论是在职充电还是为转行跳槽做准备,选择一个专业技能进行培训学习,都是非常可取的.在能力至上的今天,单凭学历已经不能成为入行敲门砖,特别是在互联网企业,通常在面试过程中就会考核技术能力,此外看你的项目作品,可见技术能力在招聘中是最具说服力的.华清远见教育职业规划专家表示零基础java培训靠谱吗,如果不清楚学什么技术更好,可以访问这里做职业规划,此外还可以通过试学来了解自己对技术课程的兴趣点. 华清远见教育开设的面向零基础人群提供的,从学习到就业一站式的浸入式

Java开发的基础条件:

------------Java开发的基础条件:Java相关的基础+对编程的自己的理解+调试代码+自己的坚持 一定要谦逊,不人云亦云,不去妄言某一门语言或技术好或坏!不是哪门技术有问题,而是(不会用才是问题,) 如何夯实(Java)编程基础,并深入学习和提高?多写,多用,多想.纸上写来终觉浅,唯有编码才是真.你觉得你的基础薄弱!那么你就应该知道你的哪些地方薄弱,什么对你现在 是最重要的,一口气吃不成个大胖子,21天你也精通不了一门编程语言, 基础知识真的很重要,很重要,很重要,重要的事情说三遍.