Java动态数组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java动态数组相关的知识,希望对你有一定的参考价值。

呃,知道长度大小是可变的,动态的,但具体点是什么?就是一个可以随意改变大小的数组?
求涵义及动态数组简单的使用代码
……另外,ArrayList<E>是啥意思?E又是什么?

ArrayList就是一个可以变成的数组(你可以这样理解)
ArrayList<E> 其中E是一个泛型,例如,ArrayList<String> array=new ArrayList<String>();则表示新建一个存放String的可变长数组。
ArrayList<Object> array1=new ArrayList<Object>()则为一个存放Object的可变长数组。
记住,这种样式的E,有的用T表示,它的意思为泛型。泛型是什么就不介绍了。
而且,E只能是一个类的类名,如果你是变为ArrayList<int>则是错误的,要用ArrayList<Integer>才可以
参考技术A Java动态数组是一种可以任意伸缩数组长度的对象,在Java中比较常用的是ArrayList<E>,其中<E>是表示泛形,即这个列表只能存放<E>的实例,如:ArrayList <String> list = new ArrayList<String>();那这个list只能存放String。

一般情况,数组定义后就不能改变大小。但很多场景又需要可以改变大小的数组。
他虽然是动态数据,在底层其实还是数组,只不过在数组快要存放满的时候,自动创建一个更大的数组。
参考技术B 理论上来讲,Java中数组声明后是不能改变其长度的,但是可以通过别的途径来实现看上去是改了变数组长度的效果.
在JDK1.6版以后提供了Arrays.copyOf(arr, newLength)方法,例:
String[] arr = "a","b","c","d","e";
arr = Arrays.copyOf(arr, 10);
这两句结果是把数据Arr的长度改为10.
实际上,第二个Arr是在堆中重新划分出一个区域,将第一个Arr的内容拷贝过来,
并补齐数据位.这时的Arr已经不再是上面的Arr了.

ArrayList<E>,是有序集合的一种型式(泛型),在JDK1.5之后提供,它规定了这个集合是存放的数据是什么类型.
参考技术C JAVA中的数组没有动态的
要是想用动态的数据结构就用向量Vector

采用Vector
import java.until.Vector;

例如:
Vector vet==new Vector();
String str="test1";
double t1=0.124;
vet.add(str);
vet.add(String.valueOf(t1));
可以用 vet.size()获取其大小。
通过vet.get(i);获取第i个元素(i从0开始),类型为Object,转换一下就可以了。
具体可以查看jdk api文档
参考技术D import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Test

/**
* @param args
*/
public static void main(String[] args)

//List,Map,Set都是集合,E为泛型,也就是数据类型理解吧。ArrayList是List的一个子类。
//一旦定义好泛型,在添加数据的时候,就只能添加定义好的类型,不能添加别的。
//你还可以去看一下队列,先进先出,后进先出,因为不常用,我也记不太清了。

//可一直往下加,有序集合,
List<String> test=new ArrayList<String>();
test.add("a");
test.add("b");

for(String t:test)

System.out.println(t);


for(int i=0;i<test.size();i++)

System.out.println(test.get(i));


//key,value。无序集合。取值的时候,可以根据key取值,也可根据value取值。
Map<String,String> map=new HashMap<String,String>();

map.put("a", "1");
map.put("b", "2");

for(String m:map.keySet())

System.out.println(m);


for(String m:map.values())

System.out.println(m);



Set<String> sets=new HashSet<String>();

sets.add("a");

sets.add("b");

for(String set:sets)
System.out.println(set);





[JAVA冷知识]动态加载不适合数组类?那如何动态加载一个数组类?

写在前面


  • 今天和小伙伴分享一些java小知识点,主要围绕下面几点:
  • 既然数组是一个类,
  • 那么编译后类名是什么?类路径呢?
  • 为什么说动态加载不适合数组
  • 那应该如何动态加载一个数组?
  • 部分内容参考
    • 《编写高质量代码(改善Java程序的151个建议)》
    • 《深入理解Java虚拟机》

君子不妄动,动必有道。君子不徒语,语必有理。君子不苟求,求必有义。君子不虚行,行必有正 ——烽火戏诸侯《剑来》


一、既然数组是一个类,那么编译后类名是什么?

通下面的代码我们可以看出,对于基本类型数组,编译后为[+基本类型标识,对于引用类型为[L+引用类类路径

package com.liruilong;

import java.util.logging.Logger;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/9  3:08
 */
public class ArrayDemo 
    static Logger logger = Logger.getAnonymousLogger();

    public static void main(String[] args) 
        logger.info("基本类型数组编译后类名:" + int[].class.getName());
        logger.info("引用类型数组编译后类名:" + String[].class.getName());

    


二月 09, 2022 3:57:03 上午 com.liruilong.ArrayDemo main
信息: 基本类型数组编译后类名:[I
二月 09, 2022 3:57:03 上午 com.liruilong.ArrayDemo main
信息: 引用类型数组编译后类名:[Ljava.lang.String;

Process finished with exit code 0

java中数组是一个较为特殊的类,不管是基本类型数组,还是引用类型数组,都没有可追溯的类路径

数组元素类型及编译后的类型

元素类型编译后的类型
byte[][B
char[][C
Double[][D
Float[][F
Int[][I
Long[][J
Short[][S
Boolean[Z
引用类型(如String)[L引用类型

二、为什么动态加载不适合数组

动态加载

关于动态加载,这里不多讲,相信小伙伴么都不陌生,在原始的JDBC编程连接数据库的时候,通常会通过静态块动态的加载一个连接数据库的驱动类,这里会用到Class.forName(driver),将驱动类加载到内存中。

当然这里forName只是把一个类加载内存中,并不是产生一个实例对象,也不会执行任何方法,具体的注入的驱动类如何生成对象,如何注册到DriverManager,一般可以通过静态块的方式实现,即类加载的同时生成实例对象并注册

我们知道在类加载(加载,验证,准备,解析,初始化)的最后一步类初始化的时候,执行类构造器<clinit>()方法,<clinit>()方法编译器自动收集类中的所有类变量的赋值动作的和静态语句块的中的语句合并产生的。编译器收集的顺序是由语句中源文件中出现的顺序决定。

下面是mysql驱动类的源码

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.mysql.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver 
    public Driver() throws SQLException 
    

    static 
        try 
            DriverManager.registerDriver(new Driver());
         catch (SQLException var1) 
            throw new RuntimeException("Can't register driver!");
        
    

为什么不适合数组

关于动态加载,小伙伴可以看看《深入理解Java虚拟机》,回到我们的问题,为什么数组不适合动态加载,由上面的代码可以知道,当使用forName加载一个类时,需要一个类的全路径,或者说全限定名

但是不管是基本类型数组,还是引用类型数组,都没有可追溯的类路径,不是一个具体的类,所以在加载的时候,会报错java.lang.ClassNotFoundException

package com.liruilong;


import java.util.logging.Logger;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/9  3:08
 */
public class ArrayDemo 
    static Logger logger = Logger.getAnonymousLogger();

    public static void main(String[] args) throws ClassNotFoundException 
        Class.forName("java.lang.String[]");
        Class.forName("int[]");
    



Exception in thread "main" java.lang.ClassNotFoundException: java/lang/String[]
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:264)
	at com.liruilong.ArrayDemo.main(ArrayDemo.java:19)

Process finished with exit code 1

直接加载不可以,那么加载一个数组编译后的类型是否可行呢?我们来看看

package com.liruilong;


import java.util.logging.Logger;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/9  3:08
 */
public class ArrayDemo 
    static Logger logger = Logger.getAnonymousLogger();

    public static void main(String[] args) throws ClassNotFoundException 
        Class.forName("[Ljava.lang.String;");
        Class.forName("[I");
    



Bad level value for property: .level
Bad level value for property: java.util.logging.ConsoleHandler.level

Process finished with exit code 0

通过上面我们可以知道,可以加载编译后的类路径动态加载一个对象数组,但是没有意义。并不能通过newInstance()方法生成一个实例对象,在java中数组是定长的,没有长度的数组是不允许存在的。

package com.liruilong;


import java.util.logging.Logger;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/9  3:08
 */
public class ArrayDemo 
    static Logger logger = Logger.getAnonymousLogger();

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException 
        Class<String[]> aClass = (Class<String[]>) Class.forName("[Ljava.lang.String;");
        String[] strings = aClass.newInstance();
    



Bad level value for property: .level
Bad level value for property: java.util.logging.ConsoleHandler.level
Exception in thread "main" java.lang.InstantiationException: [Ljava.lang.String;
	at java.lang.Class.newInstance(Class.java:427)
	at com.liruilong.ArrayDemo.main(ArrayDemo.java:20)
Caused by: java.lang.NoSuchMethodException: [Ljava.lang.String;.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.newInstance(Class.java:412)
	... 1 more

Process finished with exit code 1

三、如何动态加载一个数组

那如何通过类似动态加载的方式生成一个数组,我们可以使用Array数组工具类来动态加载一个数组。

package com.liruilong;


import java.lang.reflect.Array;
import java.util.logging.Logger;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: https://liruilong.blog.csdn.net/
 * @Date: 2022/2/9  3:08
 */
public class ArrayDemo 
    static Logger logger = Logger.getAnonymousLogger();

    public static void main(String[] args)  
        String [] strings = (String[]) Array.newInstance(String.class,6);
        logger.info("String数组长度:"+strings.length);
        int[][] ints = (int [][])Array.newInstance(int.class,6,3);
        logger.info("int数组长度:"+ints.length);
    



Bad level value for property: .level
Bad level value for property: java.util.logging.ConsoleHandler.level
Can't set level for java.util.logging.ConsoleHandler
二月 09, 2022 5:15:12 上午 com.liruilong.ArrayDemo main
信息: String数组长度:6
二月 09, 2022 5:15:12 上午 com.liruilong.ArrayDemo main
信息: int数组长度:6

Process finished with exit code 0

看看源码,我们会发现这是一个本地方法,通过C或者C++之类的语言实现的

 public static Object newInstance(Class<?> componentType, int length)
        throws NegativeArraySizeException 
        return newArray(componentType, length);
    
private static native Object newArray(Class<?> componentType, int length)
        throws NegativeArraySizeException;

关于数组的动态加载和小伙伴们分享到这里,生活加油哦 _

以上是关于Java动态数组的主要内容,如果未能解决你的问题,请参考以下文章

关于java中的toArray()方法动态数组的运用???????

关于java中动态数组的toArray()方法的运用????

java怎么动态的往一个Long数组里加入Long元素

java中如何创建动态数组

[JAVA冷知识]动态加载不适合数组类?那如何动态加载一个数组类?

Java实现动态数组(数据结构与算法)