Java基础笔记(个人总结)

本文详细总结了Java基础,包括语法特性、面向对象编程概念、异常处理、集合框架及IO流等核心知识点,结合个人编程经验深入浅出地阐述了每个主题的理解与应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 *
    * 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::】
    *
    *

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值