*
* 1.第一次遇见Person的时候,进行类的加载(只加载一次)
* 2.创建对象,为对象在堆中开辟空间
* 3.为对象进行属性的初始化动作
*
* new关键字实际上是在调用构造方法(构造器)
* 调用构造器时,如果没有写构造器,会默认分配一个构造器,构造器的作用不是为了创建对象,
* 因为在调用构造器前对象已经创建好了,并且属性有默认的初始化的值,调用构造器的目的是
* 为了给属性赋值。但是一般不会在空构造器中初始化,那样的话每个对象的属性值都一样了
* 一般在重载的构造器中赋值,加入重载后没写空构造器就不能调用空构造器了
*
* this始终指向的是当前对象
* 在同一个类中,方法可以互相调用,this.add() this可以省略
* 同一个类中构造器可以互相调用,但是this修饰的构造器必须放在第一行
* this可以修饰:方法 属性 构造器this(age)
*
* static修饰:属性 方法 代码块 内部类
* 1.类加载的时候一起载入方法区的静态域中
* 2.先于对象存在,即使没有对象也可以访问
* 3.访问方式:对象. 类型.(推荐方式)
*
* static应用场景:某些特定的数据需要在内存中共享,只有一份,如学校都一样
* 可以static String school; 方法中写Student.school = "文华学院";
*
* 所以属性可分为:
* 静态属性(类变量)
* 非静态属性(实例变量)
*
* (static和public是并列关系,没有先后顺序)
* 在静态方法里不可以访问非静态属性?为什么呢?
* 答:因为静态的static修饰的东西如:属性和方法是先于对象加载的,此时如果没
有对象你是怎么访问呢!非静态的属性和方法还没有加载,这是一个时间不同步的问题。
*
* 在静态方法中不能使用this
*
* 代码块:普通块,构造块,静态块,同步块(多线程)
* 普通块:在方法中,限定了局部变量的作用范围 {}
* 构造块:在方法外 {}
* 静态块:前面有static修饰 static{}在静态块中只能访问静态属性和方法
*
* 代码块执行顺序:
* 1.静态块,一般用于数据库初始化,创建工厂,用于一些全局性的初始化操作
* 2.构造块(不常用)
* 3.构造器
* 4.普通块(方法中的)
*
* 包名:
* 1.名字全用小写
* 2.中间用.隔开,隔开一下就是一个目录,其实的是盘符中的目录,所以不能使用系统中的关键字
* 3.一般是公式域名的倒写加上module:com.matrix.login
* 4.就是为了定位文件的位置,同一个包下的类不需要导包
* 5.java.lang下的包不需要导包
* 6.java中的包没有包含与被包含的关系,是平级的
* 7.静态导入的问题import static java.lang.Math.*;
例子:Garage\Oop\src\com\ops\Test.java
*
* 继承:is-a关系
1.提高代码的复用性,父类定义的内容,子类直接可以拿过来使用
2.子类具备扩展性
3.一个子类只能有一个直接父类
4.继承具有传递性:Student--->Person--->Object
*
* super:
1.super指代父类的
2.在父子类关系中,super可访问父类属性和方法
3.super可调用父类构造方法,用于构造父类以做好准备
THINK:创建对象后要调用构造方法初始化成员变量,那么对于父类中的
成员变量就需要使用父类的构造方法
*
* Object类
1.所有的类都直接或者间接的继承自Object类,Object是java所有类的根基类
* 2.toString()对对象的自我介绍:com.oop1.Student@4554617c
com.oop1.Student 全限定路径
4554617c hashcode将对象在堆中的地址进行哈希算法,返回一个哈希码
对象--->堆中分配地址--->进行哈希操作--->哈希码--->转成十六进制--->String
*
重写toString() 子类重写之后就调用子类的
重写equals()
@override
* public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Double.compare(student.height, height) == 0 &&
name.equals(student.name);
}
*
* 类和类之间的关系:
1.将类作为另一个类的方法形参
2.将一个类作为另一个类的属性
3.继承、实现
*
//从子类往上抽取父类叫:泛化 父到子叫:继承
* 多态:
1.多态指的是方法,与属性无关
多态就是多种状态,同一行为在不同类中表现出不同的状态,多态指的是同一种
方法的调用,根据对象不同产生不同的行为
Animals animals = new Dog();
左侧:编译期的类型
右侧:运行期的类型
2.多态的要素:
继承
重写
父类引用指向子类
向下转型,为了获取子类中特有的内容,父类只能看到有限的东西
*
*
* final修饰符:
1.final修饰变量
2.final修饰方法,不可被子类重写
3.final修饰类,子类不能继承extends,那么里面的方法就没有必要用final修饰
查看Math类,构造器也是private修饰,那么就不能被实例化,private修饰的只能在
当前类中有效,但方法和属性用了static修饰,所以可以类名.调用
*
*
* 实现implements是has-a的关系,具备某种功能、能力 (飞机、小鸟、风筝)
*
接口和抽象类的区别?
* 抽象类不能创建对象,但有构造方法。在抽象类中定义抽象方法,是为了给子类一个模板
子类可以在这基础上进行开发。抽象类为了避免子类设计的随意性,通过抽象类,子类的设计
变得更加严格,起到限制。
抽象类:
1.抽象类不能创建对象,那么抽象类是否有构造器?
一定有构造器,构造器的作用,子类初始化对象的时候要调用super();
2.抽象类可以被final修饰?
抽象类设计的初衷就是子类继承,final修饰的类不能被继承
* 静态方法不可以重写。
为什么要在接口中加入非抽象方法?
如果只能定义抽象方法,那么接口中的内容修改了,所有实现类都有影响,想加功能
就可以加
*
* 接口:
1.接口和类是同一层次的概念
2.接口中没有构造器
3.jdk1.8之前接口中只有
常量:public static final
抽象方法:public abstract
*
* 接口的作用:
* 1.和抽象类一样定义规则,不同的是它是接口不是类,定义好规则实现就好
* 2.继承:子类对父类的继承 is-a 对付类代码复用
* 3.实现:实现对接口的实现 has-a 使它具备某种能力
* 注:手机是不是照相机,如果继承则可以说:手机是一个照相机
*
* 案例:飞机 小鸟 风筝
*
多态的应用场景:
1.父类/接口当作方法的形参,传入具体的子类对象
2.父类/接口当作方法的返回值,返回具体的子类对象
*
* 类:
* 1.类的组成:属性 方法 构造器 代码块(普通块、静态块、构造块、同步块[线程]) 内部类
* 2.内部类:成员内部类 和 局部内部类(可以放在方法、块、构造器内)
*
* 内部类可以访问外部类的属性和方法
匿名内部类
匿名就是这个类没有名字,直接接口创建实现类,返回一个匿名内部类对象
*
* 异常:
1.基于if-else处理异常缺点太多,引入try-catch-finally
2.把可能出现异常的程序放在try代码块中,封装为异常对象,由Exception e接收
后续代码正常执行。
注:try中出se现异常,catch捕获成功,try中后续代码不执行
try中出现异常,try-catch后的代码正常执行
在什么情况下,try-catch后的代码不执行
1.throw抛出异常
2.catch中没有正常的进行异常捕获
3.在try中遇到return
finally:
异常处理不完善,但try-catch后的代码必须执行,放在finally中
return和finally的执行顺序,finally在前,finally中的代码无论如何
都会执行。
只有一种情况finally中的代码不执行:
System.exit(0);意思是终止虚拟机的执行
什么代码会放在finally中呢?
关闭书库据资源,关闭IO流,关闭Socket资源...
多重异常捕获
在安排catch中异常的顺序时先子类异常后父类异常
异常可以并列用 "|"
throw和throws
throw异常再现,throws谁调用谁解决
位置:throw在方法内,throws在方法声明处
内容不同:
throw+异常对象(运行时,检查时异常)
throws+异常类型(可以多个类型,逗号隔开)
作用:
throw:异常源头
throws:在方法生命出,告诉方法调用者,这个方法中可能出现我声明的这些异常
然后调用者对异常处理(自己处理或者往外抛)
*
* 重载和重写关于异常
重载,与异常无关
重写,发生在父子类中,要求子类异常<=父类异常
*
* 自定义异常可以继承运行或检查时异常,如果继承运行时异常无需额外处理,如果是检查时异常
那么使用时要捕获异常,防患于未然。
*
对于自定义的异常要继承Exception或者运行时异常类,也想打印异常提示信息,那么构造方法
时,传入的message变量只需要调用父类的方法super(message);即可,因为Throwable中已经定义了
那么对于父类变量就需要父类使用父类的构造。message属性来自于父类!
包装类(继承关系)
Integer--->Number--->Object
.
.
.
Character--->Object
Boolean--->Object
* 包装类就是对基本类型的封装,成就了包装类
1.自动拆装箱时JDK1.5之后出现的。
2.就是将基本数据类型和包装类型进行的类型转换
//valueOf将数值转为Integer过程中发生的事情:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
*
Integer a = 9;
* Integer b = 9;
底层在比较时先调用valueOf自动装箱,然后使用equals方法比较。equals底层就是==
*
* Math.random()底层还是调用的是Random对象的nextDouble()方法
*
* 字符串常量在编译时会优化,常量池的特点是第一次如果没有这个字符串,就放进去,如果有就
直接去取常量池中的
* String str = new String("abc");
常量池中有"abc" 堆中有str指向的对象,开辟了两个空间
有字符串变量参与的字符串拼接,不会直接合并
字符串的不可变是指在地址不变的情况下追地址会指向另一个,不可变字符串是在append的情况
下,StringBuilder对象的属性value的地址始终没有变。变得是value数组
底层属性:StringBuilder的 char[] value;存储字符 int count;数组已经使用的字符个数。类比ArrayList
扩容1.5倍,Vector源码,扩容为2倍,线程安全,已经淘汰。
数据结构:
线性结构(紧密结构):寻址快,增加删除元素慢,需要移动元素
链式结构(跳转结构):单向链表、双向链表、循环链表。增加和删除效率低
*
* 集合是对多个数据进行存储操作的,简称容器,这里的存储是内存结构上的
*
* jdk1.8对于ArrayList的扩容:在添加元素时才使原来的{}集合变为size为10的集合
其中elementData = Arrays.copyOf(elementData(空), newCapacity(10));成功将原来的{}
扩容为(初始化为)size为10的集合,而jdk1.7默认初始化就是size为10
*
*
* 自定义泛型:就是一个泛型类
* E这个类型现在不确定,但一定是一个引用类型,是一个占位符
* 只是类型现在不确定
*
* 泛型类的继承 指定父类泛型,子类就不需要指定,如果没有指定,就在子类创建对象时确定
*
* 细节:
* 泛型中的静态方法,不能使用泛型参数,因为泛型类型是创建对象时确定
* 泛型方法:
* 并不是参数列表带泛型就是泛型方法
* 泛型方法的要求:这个方法的参数类型要与当前类的泛型无关,跟当前类是不是泛型类无关
* 1.泛型方法在定义时前面要加上<T>
2.T类型在调用方法时才确定
3.泛型方法可否为static
* ?通配符的使用
public void a(List<?> list){}
*
List<Object> l1 = new ArrayList<>();
List<String> l2 = new ArrayList<>();
List<Integer> l3 = new ArrayList<>();
//引入通配符
List<?> list = null;
list = l1;
list = l2;
*
* 泛型受限:
List<? extends Person> 泛型上限
List<? super Person> 泛型下限
* 泛型上限 用来限制存入父子类关系的元素的上限,最高是Person
* 泛型下限 用来限制存入父子类关系的元素的下限,最低是Person
*
* 增加 删除 修改 查看 判断
* LinkedList removeFirst()和pollFirst()的区别后者即使删除没有元素的集合不会报错
*
*
* 迭代器 节省内存 这个its只在for循环结束,its只在for循环的作用域内,for循环结束变量消失
而上面的it在方法结束后才消失
for(Iterator its = list.iterator();its.hasNext();){
System.out.println(its.next());
}
*
*
* Iterable是接口,其中定义了一个抽象方法iterator()
*
* ListIterator<String> it = list.listIterator();解决遍历和操作集合,用迭代器遍历时
同时删除等操作不能实现,就是用ListIterator,事情由一个人做
it.hasNext() 使cursor到底
* it.previous() 使cursor上移 可实现逆向遍历
*
* 关于HashSet的疑问?
1.数组的长度是多少
2.数组的类型是什么?
3.hashCode,equals方法真的调用了吗?
4.底层表达式是什么?
5.同一个位置上的数据怎么放
6.放入数组中的数据,是直接放的吗?是否封装为对象?
*
* hashSet无序存放LinkedHashSet有序,就是在HashSet的基础上多了一个总的链表,将放入的
元素穿在一起
*
比较器,根据返回int值比较:
内部比较器:实现comparable接口重写compareTo()方法
外部比较器:写在类的外部,实现comparator接口,重写compare方法
* 提供的类型都有自己的比较器,都继承了Comparable接口并且实现了compareTo()
但对于自定义的类型没有自己的比较器,就需要实现Comparable接口,这种方式叫内部
比较器。
外部比较器:实现Comparator接口
TreeSet中的元素有序且唯一,对放入的元素要比较排序那么它的有序是怎么实现的?
对于Integer,String类型都有对应的比较器实现,而自定义的就需要实现Comparable
或者使用Comparator。无论是内部还是外部比较器,所有向TreeSet中放入的自定义类型
元素都得重写compareTo()
*
* entrySet() 返回的Set集合中每一个都是Math.Entry接口的实现类.其中将每对key-value封装为
对象,其中有对key和value操作的方法
* HashMap特点:无序且唯一,底层key遵照哈希表结构(数组[容量]+链表[桶])
哈希表原理:要求对放入的自定义类,必须重写equals()和hashCode(),通过hashCode计算
哈希值借助表达式计算存储位置,如果放在同一个位置要进行元素的比较。
因为HashMap无序,唯一,想有序的输入输出就使用LinkedHashMap,底层维护了一个链表
将HashMap换成HashTable依然可以实现HashMap的所有功能。后者版本更早,效率低,线程安全
HashTable存入null时不可以的。报空指针异常。
*
* TreeMap原理:二叉树,key遵循二叉树的特点,放入集合中的实例需要实现比较器接口
* HashSet底层是HashMap,存储的时候指利用key位置,value位置都用PRESENT = new Object()占位
TreeSet底层是TreeSet,存储的时候指利用key位置,value位置都用PRESENT = new Object()占位
HashMap加载因子为什么是0.75
如果设置为1,空间利用率高,但很容易hash碰撞,产生链表,查询效率低
如果设置为0.5,发生碰撞几率低,就会扩容,产生链表几率低,查询效率高,空间
利用率低。所以取了一个折衷0.75
为什么HashMap主数组长度为什么必须是2^n?
1.h & (length - 1)等效 h%length操作,等效的前提是length必须是2的整数倍
2.防止计算的存储位置冲突,容易产生链表,效率低
* 位运算?
*
* IO:不要用字符流读取非文本文件
文本文件:txt .java .c .cpp --->建议使用字符流读取
非文本文件:.jpg .mp3 .mp4 .doc .ppt---->建议使用字节流
*
* 文件是UTF-8进行存储的,所以英文字符底层占用1个字节,但是中文字符底层占用3个字节
那么对于文本文件的读取,使用字符流,防止编码拆分
非文本文件使用字节流,文本使用字符流
* 区分流通过后缀
System.in获取一个标准的输入流 默认是键盘输入
System.out获取一个标准的输出流 默认输出到控制台
理解转换流存在的目的!
DataOutputStream:数据流,就是用来操作基本数据类型和字符串的
* 序列化:ObjectInputStream和ObjectOutputStream可以将java中的对象写入到数据源中,
也可以还原也可以。也可以操作变量
* ObjectOutputStream:将内存中的Java对象转换为与平台无关的二进制数据,从而允许把这种数据
持久在磁盘上,或通过网络将这种二进制传输到另一个节点--->序列化
ObjectInputStream:当其他程序获取了这种序列化后的二进制数据,可通过此类恢复为Java对象
即--->反序列化
对于自定义类实现序列化接口,序列化用来表明类版本之间的兼容性,进行控制
接口内部什么都没有,这种接口叫--标识接口,起到标识作用,如序列化接口
序列化细节:
1.序列化的类内部所有的属性,必须是可序列化的(基本数据类型都可)
2.static,transient修饰的属性不可被序列化(想要保护的东西,不想被序列化可以用
transient修饰,银行卡号...)
*
* 线程创建的前两种方式有不足:
1.没有返回值
2.不能抛出异常
* 基于以上创建线程方式的不足jdk1.5之后出现了实现Callable接口的方式,但比较麻烦
*
join():将其他线程阻塞,执行完之后才能执行其它线程 要先调start才有效
* sleep():人为的制造阻塞,不释放cpu
* setDaemon(true);将子线程设为主线程的守护线程,主线程执行完也就伴随结束
* 主线程结束后子线程还会执行一点点---垂死挣扎
* stop():提前结束线程-->死亡
*
线程安全问题:
原因:多个线程在争抢资源过程中,导致共享资源出现问题,一个还没有执行完
另一个就参与进来
* 同步代码块能发生CPU切换吗?可以,但是对锁是不释放的,等再次获得CPU执行完才释放
多个代码块使用了同一个锁(同步监视器),所著一个代码块的同时,其他的使用该锁的代码块
也无法访问
*
* 对于同步监视器,使用的锁必须是唯一的,尽量不要使用(final修饰)包装类或其他引用类型,基于实现
Runnable接口创建多个线程和基于继承Thread创建的线程对象,前者只有一个线程对象,而后者可能有多个
所以this在使用的时候要注意,一般使用类的.class形式加锁。
* 非静态同步方法的同步监视器是this
静态方法的同步监视器是 类.class字节码信息对象
同步代码块效率高于同步方法,如果用其他的使用,被锁的同步方法其它就不能使用
*
锁具有唯一性,破环了唯一性原则,那么依旧会有抢占CPU的现象
* jdk1.5之后引入Lock锁,与synchronized相比可以提供更多锁方案,更灵活。synchronized是java关键字
是JVM识别的,是虚拟机级别。而Lock是API级别
* Lock是显示锁,synchronized是隐士锁,使用Lock锁JVM花费较少的时间调度线程,性能更好,具有更好的扩展性
效率:
Lock > 同步代码块 > 同步方法
*
* 线程同步的缺点:
线程安全,效率低。线程安全可能会造成死锁
死锁:不同线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,形成死锁
出现死锁,不会出现异常不会提示,只是所有的线程都处于阻塞状态,无法继续
* 避免死锁出现就要避免嵌套同步
*
* wait()要配合synchronized和notify()使用
*
线程通信用wait和notify,配合synchronized实现,仅有一对线程遵循生产消费者模型时,是可行的,但是如果
出现多对生产者消费者,那么notify之后的结果将会唤醒wait set中的所有线程,将打破生产消费模式,所以jdk1.5
之后引入Lock的Condition替换传统的Object的wait和notify线程协作(java中每个对象都可以承担锁的功能)
与传统的相比,Condition的await和signal方法更加高效。可以拥有一个同步等待队列和多个等待队列,但这些
都必须使用在lock.lock()和lock.unlock()之间才可以使用,传统的必须放在同步方法或者同步代码块中。
*
* 网络编程:
TCP 客户端服务端地位不平等
客户端套接字:Socket 通过流发送
服务端套接字:ServerSocket-->Socket 通过流接收
UDP 地位平等
发送发:DatagramSocket 数据包发送DatagramPacket
接收方:DatagramSocket 数据包接收DatagramPacket
*
* 网络通信中TCP通信,Socket是唯一的,不能重复创建
UDP中new DatagramSocket(8888)是唯一的不能重复创建
*
* 框架=注解+反射+设计模式
* Annotation 可以像修饰符一样,可用于修饰包、类、构造器、方法、成员变量、参数
局部变量的声明。这些信息会保存在Annotation的name=value对中,在JavaSE中,注
解使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解
占据了更重要的角色,例如配置程序的任何切面,代替JavaEE旧版本中遗留的繁冗代码和XML
配置等 。未来开发基于注解的,JPA(java持久化API)是基于注解的,Spring2.5以.E基于
注解的,现在的struts2有一部分也是基于注解的,从一定程度来说:框架=注解+反射+设计模式
JDK内置的三个注解
@override
@deprecated修饰类、方法、构造器属性前,不赞成使用---已过时
@SupportWarnings抑制(取消)编译器警告
*
* 内部没有定义参数的注解叫--->标记
内部定义参数的注解叫--->元数据
*
* 修饰注解的注解--元注解
JDK1.5提供了四个元注解:Retention,Target,Documented,Inherited
Retention
* 属性: RetentionPolicy.SOURCE只在源文件有效
* RetentionPolicy.CLASS在字节码文件有效
* RetentionPolicy.RUNTIME在运行时有效
如果注解没有加Retention元注解默认生命周期在字节码文件有效
* Target
定义可以修饰的目标
* Documented
* 被它修饰的注解会被提取到API文档中
Inherited
如果使用该注解修饰定义的注解就具备了继承性,相当于子类也是用了
该定义注解
*
* 枚举类:在java类中类的对象是有限个 ,确定的,这个类我们可以定义为枚举类
Thread中的枚举类
枚举类常用方法
枚举类实现接口
枚举类的实际应用:性别的控制、可结合switch-case使用
*
* 反射:
问题一:创建Person对象,以后用new还是反射?
在运行时才能确定使用哪个对象时,体现更好的扩展性,体现反射的
动态性,如前台传入什么请求在运行时决定
问题二:反射是否破环了面向对象的封装性?
* 看你怎么使用,在不使用反射的情况下,代码的封装性没有破坏,比如
private修饰的,但如果你要是用反射访问那就是主动的破坏了它的封装性,
还不如就定义成public。不建议使用
*
* 创建对象的方式:
new , 序列化 , clone , 反射
* 一般情况下,我们并不能对类的私有字段进行操作,利用反射也不例外,但有的时候,例如
要序列化的时候,我们又必须有能力去处理这些字段,这时候,我们就需要调用AccessibleObject
上的setAccessible()方法来允许这种访问,而由于反射类中的Field,Method和Constructor继承
自AccessibleObject,因此,通过在这些类上调用setAccessible()方法,我们可以实现对这些字
段的操作。
* 凡是基于TCP/IP协议的智能设备都会被分配IP地址。网管即路由,路由即网关,就是一个网络
通向其他网络的地址。网关可以是192.168.0.1/192.168.0.254或者172.16.0.1/172.16.0.254,
掐头去尾
*
* 1.where在分组前过滤,having在分组后过滤,两者之间不冲突。
* 2.where后不能使用聚合函数
3.各层传输数据形式
物理层---------比特(bit)
数据链路层-----帧(frame)
网络层--------包(packet,datagram)
传输层--------数据段(segment)
应用层--------报文(message)
* 4.NAT技术,是网络地址转换技术,将专用网的网络地址转换为全球IP地址,从而与外界进行通信。需要
注意的是,NAT技术可以隐藏内部网的主机,从而在一定程度上避免网络攻击,但不是主要的实现防火墙
的技术。
* 5.IPv6零压缩只能使用一次,以避免歧义
fe08::5efe:172.16.18.3 正确
5401::13::b0c:3201 压缩两次错误
* IPv6地址可以将IPv4地址内嵌进去,并且写成IPv6形式和平常习惯的IPv4形式的混合体。
*
【表述和书写时,把长度为128个二进制位(bit)的IPv6地址分成8个16位的二进制段、每一个16位的
二进制段用4位的16进制数表示,段间用“:”(冒号)隔开(其书写方法和IPv4的十进制数加“.”不同)。
例如:1000:0000:0000:0000:000A:000B:000C:000D就是每一个16位的二进制数的段用4位16进
制数的段来表示、段间用“:”(冒号)隔开的一个IPv6地址;其中:各个4位16进制数的段中的高
位0允许省略;因此,上面的IPv6地址也可以缩写成:1000:0:0:0:A:B:C:D。
为了更进一步简化,IPv6的地址规范中还规定,可以在一个IPv6地址中最多使用一次双
冒号(::)来取代IPv6地址中紧密相连的多个全0的16进制数的段(因为如果允许在一个
IPv6地址中使用一次以上的双冒号时将无法判断IPv6地址的长度,所以IPv6的地址规范
中才规定:在一个IPv6地址中最多只能使用一次双冒号),这样上面的IPv6地址还可以缩写
成:1000::A:B:C:D。双冒号使用的地点可以在IPv6地址的前面、后面或者是中间;
例如:对于1000:0:0:0:A:B:0:0这样的一个IPv6地址,可以写成1000::A:B:0:0,也可以写
成1000:0:0:0:A:B::;但是不能写成1000::A:B::】
*
*
Java基础笔记(个人总结)
最新推荐文章于 2025-04-10 18:46:03 发布