转自 https://blog.csdn.net/qq_25373015/article/details/78158102
1、JDK和JRE的区别以及跨平台的原理
JRE:java的运行环境,包括java虚拟机和java程序所需的核心类库,JVM+类库
JDK:java的开发工具包,包含java的开发工具,编译工具、打包工具等
JDK = JRE+Java的开发工具
跨平台的原理:实现跨平台需要依赖java的虚拟机JVM,不同平台使用不同的java虚拟机,实现一次编译处处运行。
2、java的关键字和标识符及其特点
java关键字:被java语言赋予特定含义的单词
特点:组成关键字的字母全部小写,常见的代码编辑器对关键会有特殊的颜色标记
标识符:给类、方法、变量等起名字
特点:由字符、下划线、美元符$组成,不能以数字开头、不能是java的关键字
3、java的数据类型和分类
分类:
基本数据类型:四类八种
引用数据类型:类、接口、数组
4、java的运算符种类
4.1、算术运算符
对常量和变量进行操作的运算符
字符参与运算:其实就是该字符对应的数值操作
字符串和其它数据类型的数组做拼接,结果是字符串类型
4.2、赋值运算符
4.3、关系运算符
关系运算符的结果都是boolean性,要么是true要么是false
4.4、逻辑运算符
4.5、三元运算符
5、&&和&的区别以及|和||的区别:
&&和&的区别
&&和&都是逻辑与运算,都是要求运算符两侧的表达式为true,结果才为true。&& 具有短路效果,当左侧的表达式结果为false时,右侧将不再执行。&是无论左侧是 否为false,将继续执行下去。&还可以用于按位与
|和||的区别
最终的结果是一样的,||具有短路效果,左侧为true,右边将不再执行,|是无论 左边是false还是true,右边都会执行
6、键盘录入的对象创建
Scannersc = new Scanner(System.in);
再调用sc.nextInt()的等函数
7、数组
数组是存储同一种数据类型多个元素的容器
两种初始化方式:
初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋值
动态初始化:初始化时只指定数组长度、并有系统为数组分配初始化值
静态初始化:初始化指定每个数组元素的初始化值,有系统决定数组长度
8、JVM的内存划分
栈:存储局部变量
堆:存储new出来的东西
方法区:
本地方法区:与系统相关
寄存器:给CPU使用
9、方法重载和方法重写
方法重载:在同一个类中,允许多个同名方法,只要他们的参数个数或者参数类型不同即可,方法名相同,参数类型不同,分为参数个数不同,参数类型不同,与返回值无关
方法重写:存在于子父类之间,子类的方法的权限修饰符权限大于或等于父类的,方法名和参数类型完全相同,与返回值有关
10、方法中的参数传递
形参为基本数据类型:形参的改变不影响实际参数
形参为引用数据类型:形参的改变会影响实际参数
11、面向对象的特征
1、封装
将客观事物封装成抽象的类,一个类就是一个封装了数据和操作的这些数据的代码 的逻辑实体
2、继承
可以让其他类型的得对象获得另一个类型的对象的属性的方法。它可以使用 现有类的所有功能,并在无需重写原来类的情况下对这些功能进行扩展
3、多态
父类或父接口引用指向的子类对象
12、面向对象的特点
更符合我们的思考方式,将事情将给其他人去做,将复杂事情简单化,我们从执行者变 成了指挥者角色
13、类与对象的关系
类:是一组相关属性和行为的集合
对象:是该类事物的具体体现
14、String、StringBuffer、StringBuilder
String:字符串常量,字符串长度不变,是被声明程final的,一次赋值不可改变
StringBuffer:字符串变量,线程安全,如果需要频繁的对字符串内容进行修改,处于效率考虑最好使用StringBuffer。StringBuffer,在任意时间点上都包含特定的字符序列,但通过方法调用改变长度和内容
StringBuilder:字符串变量,非线程安全。StringBuilder对象被当做一个包含字符序列的变长数组,是在JDK1.5后新增的,可用于字符串缓冲区被单线程使用时使用
15、String对象的两种创建方式
通过构造方法创建字符串对象是在堆内存
直接赋值方式创建对象是方法区的常量池
16、String是基本的数据类型
String类是final类型,因此这个类不能被继承,不能修改。为了提高效率节省空间,使用StringBuilder类
17、GC是什么?为什么要用GC
GC是垃圾回收的意思,内存处理是编程人员容易出现的问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,java提供的GC功能可以自动检测对象是否超过作用域从而达到自动回收的目的,java语言没有提供释放已分配内存的显示操作方法。
18、java中有几种类型的流
字节输入流:InputStream 字节输出流:OutputStream
字符输入流:Reader 字符输出流:Writer
19、什么是java序列化,如何实现java序列化
java对象的序列化是指将一个java对象写入IO流中,于此对应的是,对象的反序列化则是从IO流中恢复的Java对象。如果要让某个对象支持反序列化机制,必须让它的类是可序列化,则需要实现Serializable接口或者Externalizable接口
20、对象在序列化时不想给一个字段的数据保存到硬盘上
使用transient关键字
21、IO中的适配器模式
适配器模式:讲一个累的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作在java IO中。
BufferedReaderbr = new BufferedReader(new InputStreamReader(is2,"utf8"));
(将字节流接口,转换成字符流接口)
br.readLine();
因为要逐行解析字符串, 我们需要使用字符流,对文件内容进行处理, 所以使用Reader输入流下面的BufferedReader,BufferedReader并不能直接处理文件,它需要传入一个Reader类型的参数,Reader下面能处理文件的类:InputStreamReader,以及其子类FileReader,这2个类都需要一个InputStream来读取文件中的内容并转换, 这2个类其实就是适配器, 可以把字节流转换成字符流, 然后使用Reader来解析其中的内容
22、IO中的装饰模式
装饰模式就是对一个类进行装饰,增强其方法行为,在装饰模式中,作为原来的这个类的使用者应该感受不到装饰前和装饰后的不同。装饰模式就是对原有功能的扩展。
22、适配器模式和装饰模式的总结
适配器模式主要是将一个接口转变成另一个接口,它的目的是通过改变接口来达到重复使用的目的。装饰模式则是不是改变被装饰对象的接口,而是保持原来的接口,但是增强了元有对象的功能,或改变原有对象的方法而提高性能
23、同步和异步、阻塞和非阻塞
同步:当一个同步调用发出后,调用者要一直等待返回消息通知后,才能进行后续执行
异步:当一个异步过程调用发出后,调用者不能立刻得到返回消息。在调用结束后,通过消息回调来通知调用者是否成功
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务,函数只有在得到结果后才会返回
非阻塞:非阻塞和阻塞的概念相对应,指再不能立刻得到借过钱,该函数不会阻塞当前线程,而会立刻返回
同步和异步的重点在于消息通知的方式,也就是调用结果通知的方式
阻塞和非阻塞的重点是当前线程等待消息返回的行为
分类:同步阻塞、同步非阻塞、异步阻塞、异步非阻塞
24、进程和线程的区别
进程是正在进行中的程序。线程其实就是进程中一个程序执行控制单元,一条执行路径。进程负责的是应用程序的空间的标示。
一个进程至少有一个线程在运行,当一个进程中出现多个线程时,这个应用程序就是多线程应用程序,每个线程在栈区都有自己的执行空间,自己的方法区、自己的变量。
25、线程的运行
start方法,作用1、启动了线程,2)、让jvm调用了run方法
26、创建线程的方式
1)、继承Thread,由子类重写run方法,由run方法体来完后曾线程需要做的事
2)、实现了Runnable接口,由run方法体来完后曾线程需要做的事
3)、通过Callable和FutrueTask创建线程。创建Callable的实现类,实现call()方法,该call()方法作为线程执行体,并有返回值
创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
27、多线程安全问题
当一个线程执行多条语句时,并运算同一个数据时,在执行过程中,其他线程参与进来,并操作这个数据,导致了错误数据的产生
涉及到两个因素
1、多个线程在操作共享数据
2、有多条数据对共享数据进行运算
解决方案:
只要将操作共享数据的语句在某一个时段让一个线程执行完,在执行过程中,其他线程不能进来执行就可以解决--------使用同步代码块
28、同步的好处与弊端
好处是解决了线程安全问题,弊端是相对降低性能,因为判断锁需要资源,产生了死锁
前提:必须有两个及以上的线程才需要同步,多个线程必须保证是同一个锁
29、同步代码块和同步函数的区别
同步代码块使用的锁可以是任意对象
同步函数使用的锁是this,静态同步函数的锁是该类的字节码文件对象
在一个类中只有一个同步,可以使用同步函数。如果有多同步,必须使用同步代码块,来确定不同的锁。同步代码块相对灵活一些
30、请写一个延迟加载的单例模式?写懒汉式;当出现多线程访问时怎么解决?加同步,解决安全问题;效率高吗?不高;怎样解决?通过双重判断的形式解决。
//懒汉式:延迟加载方式。
当多线程访问懒汉式时,因为懒汉式的方法内对共性数据进行多条语句的操作。所以容易出现线程安全问题。为了解决,加入同步机制,解决安全问题。但是却带来了效率降低。
为了效率问题,通过双重判断的形式解决。
class Single{
privatestatic Single s = null;
privateSingle(){}
publicstatic Single getInstance(){ //锁是谁?字节码文件对象;
if(s== null){
synchronized(Single.class){
if(s== null)
s= new Single();
}
}
returns;
}
}
31、等待唤醒机制
wait:将同步中的线程处于冻结状态。释放了执行权,释放了资格,同时将线程对象存在线程池中
notify:唤醒线程池中的某一个等待线程
notifyAlll:唤醒的是线程池中的所有线程
32、sleep和wait的区别
wait:可以指定时间也可以不指定时间,不指定时间,只能由对应的notify或者notifyall来唤醒
sleep:必须指定时间,时间到自动从冻结状态转成运行状态(临时阻塞状态)
wait:线程会释放执行权,而且线程会释放锁
sleep:线程会释放执行权,但不释放锁
33、线程死锁的出现和解决办法
当线程任务出现了多个同步(多个锁)时,如果同步嵌套了其他的同步,这时容易引发一种现象:线程出现无限等待,都在等待对方的执行结束
解决方案:线程按照一定的顺序加锁,按照同一顺序访问对象,避免事务中用户的交互,保持事务处于一个批处理,死锁检测
34、lock和synchronize的区别
lock不是java内置的,synchronize是java的关键字,lock是一个类,通过这个类可以实现同步访问
Lock和Synchronize的最大不同:采用Synchronize不需要用户去手动加锁,当Synchronize方法或者代码块执行完成后,系统会自动让线程释放对锁的占用,而lock则必须要用户手动释放锁,如果没有自动释放锁,会出现死锁的现象
35、启动一个线程是run()还是start()?它们的区别?
启动一个线程是start()
区别:
start: 启动线程,并调用线程中的run()方法
run : 执行该线程对象要执行的任务
36、单例设计模式
两种方式
A:饿汉式:当类加载时就创建对象
class Student{
privateStudent(){}
private static final Student s = newStudent();
publicstatic Student getInstance(){
returns;
}
}
B:懒汉式 当使用的时候,才去创建对象
classStudent{
privateStudent(){}
privatestatic final Student s = null;
publicstatic Student getInstance(){
if(s==null){
//线程1进来了,线程2就进来了
s= new Student();
}
returns;
}
}
饿汉式和懒汉式的区别
饿汉式是类一加载就创建好对象,
懒汉式是类加载进内存,对象还没有存在,只有调用getInstance()方法才创建对象
懒汉式是延迟加载,如果多个线程同时操作懒汉式就可以出现线程安全问题,
开发中常使用饿汉式,因为饿汉式安全。
37、Java中创建(实例化)对象的五种方式
1、用new语句创建对象,这是最常见的创建对象的方法。
2、通过工厂方法返回对象,如:String str = String.valueOf(23);
3、运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance() 实例方法。如:Object obj =Class.forName("java.lang.Object").newInstance();
4、调用对象的clone()方法。
5、通过I/O流(包括反序列化),如运用反序列化手段,调用java.io.ObjectInputStream 对象的 readObject()方法。
38、异常
程序运行过程中的不正常现象叫做异常
异常的根类是Throwable
|--Error:重大问题,处理不了,例如JVM内存溢出
|--Exception:一般性错误,需要我们编写代码进行处理
39、异常的分类:
编译时异常
在编译时,如果没有处理,编译失败
运行时异常
在编译时,不需要处理,编译器不检查
该异常的发生,减一不处理,让程序停止,需要对代码进行修正
40、java中三种常见内存溢出错误的处理方法
jvm管理的内存大致包括三种不同类型的内存区域:Permanent Generation space(永久保存区域)、Heapspace(堆区域)、Java Stacks(Java栈)。
第一种OutOfMemoryError: PermGen space
原因是:程序中使用了大量的jar或class,使java虚拟机装载类的空间不够
解决方案:
1、增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中 XX:PermSize是初始永久保存区域大 小,XX:MaxPermSize是最大永久保存区域大小。
2、清理应用程序中web-inf/lib下的jar,如果tomcat部署了多个应用,很多 应用都使用了相同的jar,可以将共同的jar移到tomcat共同的lib下,减少类的重 复加载。
第二种OutOfMemoryError: Java heap space
原因是java虚拟机创建的对象太多,在进行垃圾回收之间,虚拟机分配的到堆内 存空间已经用满了,与Heapspace有关
解决方案:
1、检查程序,看是否有死循环或不必要地重复创建大量对象。找到原因后,修改 程序和算法。
2、增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。
第三种OutOfMemoryError:unable to create new native thread
因为JVM已经被系统分配了大量的内存,并且它至少要占用可用内存的一半
要想创建更多的线程,你必须减少分配给JVM的最大内存
41、final、finally、finalize区别
final是最终的意思,可以用于修饰类、成员变量、成员方法
它修饰的类不能被继承,修饰的变量是常量,修饰方法不能被重写
finally:是一场处理里面的关键字
它其中的代码永远会被执行,特殊情况:在执行前jvm退出
finalize是Object类中的一个方法
它用于垃圾回收器调用方式
42、什么是锁?锁的作用是什么?
锁就是对象
锁的作用是保证线程同步,解决线程安全问题。
持有锁的线程可以在同步中执行,没有锁的线程即使获得cpu执行权,也进不去。
43、什么是ThreadLocal类,怎么使用它?
ThreadLocal类提供了线程局部 (thread-local) 变量。是一个线程级别的局部变量,并非“本地线程”。
ThreadLocal为每个使用该变量的线程,提供了一个独立的变量副本,每个线程修改副本时不影响其它线程对象的副本
下面是线程局部变量(ThreadLocal variables)的关键点:
一个线程局部变量(ThreadLocal variables)为每个线程方便地提供了一个单独的变量。
ThreadLocal实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程。
当多个线程访问 ThreadLocal 实例时,每个线程维护 ThreadLocal 提供的独立的变量副本。
常用的使用可在 DAO 模式中见到,当 DAO 类作为一个单例类时,
数据库链接(connection)被每一个线程独立的维护,互不影响。(基于线程的单例)
44、集合和数组的区别
数组的长度是固定的,而集合长度是可变的
数组值可以存储对象,还可以存储基本数据类型;而集合只能够只能存储对象
数组存储的数据类型是固定的,而集合存储的数据类型不固定
45、HashSet是如何保证元素唯一性的呢?
如果两元素的hashCode值不同,则不会调用equals方法
如果两元素的hashCode值相同,则继续判断equals是否返回true;
hashCode和equals方法虽然定义在自定义对象类里面,但不是我们手动调用而是往 HashSet集合里面存储元素的时候,集合底层自己调用hashCode和equals它自己 拿对象去判断,自己判断两元素是否是同一个元素。
46、Map
Map:顶层接口,该集合存储的是键值对,而且键是唯一的,Map和Set很像,Set集合底层就 是使用了Map集合。
Map集合没有迭代器,要取出元素必须先将Map集合转换成Set集合才能遍历元素
|--->HashTable(JDK1.0):
底层是哈希表数据结构;
不可以使用null键和null值;
用作键的对象必须实现hashCode和equals方法来保证键的唯一性
线程同步,效率低
|--->HashMap(JDK1.2):
底层是哈希表数据结构;
允许使用null键和null值;
线程不同步,效率高;
保证元素唯一性的:
原理:先判断元素的hashCode值是否相同,再判断两元素的equals方法是 否为true
(往HashSet里面存的自定义元素要复写hashCode和equals方法,以保证元素的 唯一性!)
47、LisIterator、Comparable、Comparator、Collections和Arrays
LisIterator:系列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表 Comparable:此接口强行对实现它每个类的对象进行整体自然排序。使元素具备比较性
Comparator:强行对某个对象collection进行整体排序的比较函数,使集合具备比较性
Collections:此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。
Arrays:此类包含用来操作数组(比如排序和搜索)的各种静态方法
48、Map集合和Collection集合的区别?
(1)
Map中一次存储是键值对。
Collection中一次存储是单个元素。
(2)
Map的存储使用的put方法。
Collection存储使用的是add方法。
(3)
Map集合没有迭代器,Map的取出,是将Map转成Set,在使用迭代器取出。
Collection取出,使用就是迭代器。
(4)
如果对象很多,必须使用集合存储。
如果元素存在着映射关系,可以优先考虑使用Map存储或者用数组,
如果没有映射关系,可以使用Collection存储。
49、IO流常用基类方法摘要:
**字节写入流:OutputStream:
voidclose() 关闭此输出流并释放与此流有关的所有系统资源。
voidflush()刷新此输出流并强制写出所有缓冲的输出字节。
abstract void write(int b) 将指定的字节写入此输出流。
voidwrite(byte[] b) 将 b.length 个字节从指定的 byte数组写入此输出流。
voidwrite(byte[] b, int off, int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
**字节读取流:InputStream:
voidclose() 关闭此输入流并释放与该流关联的所有系统资源。
intavailable() (特有方法!!)
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过) 的估计字节数。
abstract int read() 从输入流中读取数据的下一个字节。
intread(byte[] b)从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中。
intread(byte[] b, int off, int len) 将输入流中最多len个数据字节读入byte数组。
longskip(long n) 跳过和丢弃此输入流中数据的 n 个字节。
**字符写入流:Writer:
abstract void close() 关闭此流,但要先刷新它。
abstract void flush() 刷新该流的缓冲。
voidwrite(int c) 写入单个字符。
voidwrite(char[] cbuf) 写入字符数组。
abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
voidwrite(String str) 写入字符串。
voidwrite(String str, int off, int len) 写入字符串的某一部分。
**字符读取流:Reader:
abstract void close() 关闭该流并释放与之关联的所有资源。
intread() 读取单个字符。
intread(char[] cbuf) 将字符读入数组
abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。
longskip(long n) 跳过字符。
50、流的操作流程
(1)第一步:先明确源和目的
源:
文本:用Reader
字节:用InputStream
目的:
文本:用Writer
字节:用OutputStream
(2)第二步:明确是不是纯文本
是:用字符流;
不是:用字节流
(3)第三步:明确流体系后,通过设备来明确具体使用哪个流对象
源设备:
键盘:System.in
硬盘:文件流File
内存:数组流ArrayStream
目的设备:
键盘:System.out
硬盘:文件流File
内存:数组流ArrayStream
51、File类常见需求:
(1)文件名过滤:列出给定目录的所有.java文件
publicvoid showFileName(File file)
{
String[]filenames = file.list(new FilenameFilter()//匿名内部类
{
publicboolean accept(File dir,String name)//复写唯一方法
{
returnname.endsWith(".java");//列出所有.java文件
}
});
}
(2)列出指定目录下的所有文件和文件夹(递归)
**示例1:不带层次递归:
publicstatic void showDir(File dir)
{
File[]files = dir.listFile();
for(inti = 0;i<files.length;i++)
{
if(files[i].isDirectory&&!files[i].isHidden())
showDir(files[i]);
else
sop(files[i]);
}
}
**示例2:带层次递归:
publicstatic void showDir(File dir,int level)
{
sop(getLevel(level)+C);//进来先打印层次和目录
level++;
File[]files = dir.listFile();
for(inti = 0;i<files.length;i++)
{
if(files[i].isDirectory&&!files[i].isHidden())
showDir(files[i]);
else
sop(getLevel(level)+files[i]);//是文件就打印层次和目录
}
}
publicstatic String getLevel(int level)
{
sop("|--");
StringBuildersb = new StringBuilder();
for(inti=0;i<level;i++)
{
sb.inset(0."| ")
}
returnsb.toString();
}
(3)需求:删除带内容的目录:
publicstatic void removeDir(File dir)
{
File[]files = file.listFile();
for(inti = 0;i<files.length;i++)
{
if(files[i].isDirectory&&!files[i].isHidden())
removeDir(files[i]);//如果是文件夹则继续调用函数
else//如果是文件则删除。注意删除的时候打印删除的结果,防止误删或者重删的情况
sop(files[i].toString()+"::"+files[i].delete());
}
sop(dir+"::"+dir.delete());
}
(4)需求:将制定目录下java文件的绝对路径存储到文本文件中。
思路:
**对指定目录进行递归
**获取递归过程中所有java文件的路径
**将这些路径存储到集合中
**将集合中的数据写入文件中
//对指定目录进行递归并将所以Java文件存储到集合中
publicstatic void getFileName(File file,ArrayList<File> arraylist){
File[]files = file.listFiles();
for(int i = 0; i < files.length; i++) {
if(files[i].isDirectory()&&!files[i].isHidden()){
getFileName(files[i],arraylist);
}else{
if(files[i].getName().endsWith(".java")){
arraylist.add(files[i]);
}
}
}
}
//将集合中所有数据存储到新文件中
publicstatic void saveFileToNewDir(ArrayList<File> arraylist,File newDir){
BufferedWriterbufw = null;
try{
bufw= new BufferedWriter(new FileWriter(newDir));
for(File file : arraylist) {
StringfileAbsolutePath = file.getAbsolutePath();
bufw.write(fileAbsolutePath);
bufw.newLine();
bufw.flush();
}
}catch (Exception e) {
System.out.println("文件写入失败");
}finally{
try{
if(bufw!=null)
bufw.close();
}catch (Exception e2) {
System.out.println("文件写入流关闭失败");
}
}
}
52、Properties
(1)Properties是HashTable的子类,具备Map集合的特点,里面存储的是键值对
(2)Properties是IO流合集合相结合的集合容器
(3)Properties的特点是可以用于存储键值对形式的配置文件
53、网络模型:
OSI模型
应用层、表示层、会话层、传输层、网络层、数据连接层、物理层
TCP/IP模型
应用层、传输层、网际层、主机至网络层
54、UDP和TCP的区别:
UDP
将数据及源和目的封装成数据包中,不需要建立连接
每个数据报的大小在限制在64k内
因无连接,是不可靠协议
不需要建立连接,速度快
TCP
建立连接,形成传输数据的通道。
在连接中进行大数据量传输
通过三次握手完成连接,是可靠协议
必须建立连接,效率会稍低
55、XML文档的定义形式?他们之间的本质区别,解析XML文档的方式
XMl文档定义分为DTD和Schema两种形式,二者都是对XML语法的约束,其本质的区别在于Schema本省就是一个xml文件,可以被XML解析器解析,而且乐意为XML承载的数据定义类型约束比DTD更强大。
对XML的解析主要有DOM(文档对象模型),SAX和StAX。
DOM处理大型文件时其性能下降的非常厉害,这个问题是由DOM树结构占用的内存较多造成的,而且DOM解析方式必须在解析文件之前把整个文档装入内存,适合对XML的随机访问(典型的用空间换取时间的策略);SAX是事件驱动型的XML解析方式,它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时
56、你在项目中哪些地方用到了XML?
XML的主要作用有两个方面:数据交换和信息配置。在做数据交换时,XML将数据用标签组装成起来,然后压缩打包加密后通过网络传送给接收者,接收解密与解压缩后再从XML文件中还原相关信息进行处理,XML曾经是异构系统间交换数据的事实标准,但此项功能几乎已经被JSON(JavaScriptObjectNotation)取而代之。