• 疯狂Java讲义 读书笔记(一)


    李刚老师的《疯狂Java讲义》(第三版)是我的启蒙作品,前前后后一共看了3遍,每次都有新的认识。

    接下来的一段时间就将一些经典的知识记录下来。

    1.计算机高级语言的执行方式分为编译型和解释型,前者运行高效但不能跨平台(C,C++,Object-C),后台可以跨平台但效率不高(Ruby,Python)。Java比较特殊,先编译生成.class,再在JVM中解释。

    2.垃圾回收机制:依靠垃圾回收算法,何时回收对Java程序员而言具有透明性,因此要养成良好的习惯——对于不需要的对象,不要引用他们。(在堆中进行回收)

    3.Java是强类型语言:所有类变量必须先声明后使用,指定类型的变量只能接受与类型相匹配的值。

    4.Java支持两种类型:

    1. 基本类型:布尔类型、数值类型
    2. 引用类型:类、接口、数组。

    5.强制类型转化:造成溢出时,之前一直觉得19.745会变成19(实在汗颜),其实是转换成二进制后再进行截取。

    6.常量池:在编译期被确定,并已被保存在.class文件中的一些数据。包括类、方法、接口中的常量,也包括字符串常量。

    7.switch语句:控制表达式的数据类型只能是byte,short,char,int,枚举,String.

    8.break和continue可以通过标签跳到指定的循环层

    public class BreakTest2
    {
        public static void main(String[] args)
        {
            outer:
            for (int i = 0 ; i < 5 ; i++ )
            {
                for (int j = 0; j < 3 ; j++ )
                {
                    System.out.println("i的值为:" + i + "  j的值为:" + j);
                    if (j == 1)
                    {
                        break outer;
                    }
                }
            }
        }
    }

    9.栈和堆:

    1. 当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自动销毁。因此,所有在方法中定义的局部变量都是放在栈内存中;
    2. 当我们在程序中创建一个对象是,这个对象将被保存到运行是数据区中,以便反复利用,这个运行是数据区就是堆内存。堆内存中的对象不会因方法结束而销毁,就算方法结束后,这个对象还可能被另一个变量所引用,则这个对象不会销毁,只有当一个变量没有任何引用变量引用它,那么系统的垃圾回收器才会在合适的时候回收它;

    10.Arrays:Java8增加的工具类,在java.util包下,支持并发编程

            // 定义一个a数组
            int[] a = new int[]{3, 4 , 5, 6};
            // 定义一个a2数组
            int[] a2 = new int[]{3, 4 , 5, 6};
            // a数组和a2数组的长度相等,每个元素依次相等,将输出true
            System.out.println("a数组和a2数组是否相等:"
                + Arrays.equals(a , a2));
            // 通过复制a数组,生成一个新的b数组
            int[] b = Arrays.copyOf(a, 6);
            System.out.println("a数组和b数组是否相等:"
                + Arrays.equals(a , b));
            // 输出b数组的元素,将输出[3, 4, 5, 6, 0, 0]
            System.out.println("b数组的元素为:"
                + Arrays.toString(b));
            // 将b数组的第3个元素(包括)到第5个元素(不包括)赋为1
            Arrays.fill(b , 2, 4 , 1);
            // 输出b数组的元素,将输出[3, 4, 1, 1, 0, 0]
            System.out.println("b数组的元素为:"
                + Arrays.toString(b));
            // 对b数组进行排序
            Arrays.sort(b);
            // 输出b数组的元素,将输出[0, 0, 1, 1, 3, 4]
            System.out.println("b数组的元素为:"
                + Arrays.toString(b));
        }

    11.Java语言通过new关键字调用构造器。

    12.this关键字:

    1. 让类中的一个方法,访问该类里的另一个方法或者实例变量。
    2. this所代表的对象是不确定的,但他的类是确定的。
    3. 在构造器中,this代表该构造器正在初始化的对象。
    4. 如果在某个方法中把this作为返回值,则可以多次连续调用同一个方法。
    public class ReturnThis
    {
        public int age;
        public ReturnThis grow()
        {
            age++;
            // return this返回调用该方法的对象
            return this;
        }
        public static void main(String[] args)
        {
            ReturnThis rt = new ReturnThis();
            // 可以连续调用同一个方法
            rt.grow()
                .grow()
                .grow();
            System.out.println("rt的age成员变量值是:" + rt.age);
        }
    }

    13.static:不要使用对象去调用static修饰的成员变量,要使用类去调用。

    14.值传递:将实际参数的副本传入方法内,参数本身不会受到任何影响。

    15.形参可变的方法:定义方法时,在最后一个形参的类型后增加三个点(...)。多个参数值被当成数组传入。与传入数组相比,形参可变更加简洁,但一个方法只能有一个可变形参。

    public class Varargs
    {
        // 定义了形参个数可变的方法
        public static void test(int a , String... books)
        {
            // books被当成数组处理
            for (String tmp : books)
            {
                System.out.println(tmp);
            }
            // 输出整数变量a的值
            System.out.println(a);
        }
        public static void main(String[] args)
        {
            // 调用test方法
            test(5 , "疯狂Java讲义" , "轻量级Java EE企业应用实战");
        }
    }

    16.递归算法:一个方法调用自身,一定要向已知方向递归。

    17.局部变量:形参(方法签名中定义的变量),方法局部变量(在方法内定义),代码块局部变量(在代码块内定义),局部变量不属于任何类或者实例,它总是保存在其所在方法的栈内存中。

    18.封装:类的成员变量不直接暴露,而是通过方法实现操作和访问,以便于在方法中添加一些限制条件

    19.高内聚:尽可能把模块的内部数据、功能实现细节隐藏在模块内部独立完成,不允许外部直接干预;低耦合:仅暴露少量的方法给外部使用。

    20.静态导入:JDK1.5增加的导包方法,用于导入包内的静态成员 import static package...

    21.构造器:

    1. 构造器是创建Java对象的重要途径,但这个对象并不是完全由构造器负责创建的。
    2. 子类的构造器必定会调用其父类的构造器(没有super和this时默认调用无参的构造器)。

    22.方法重写(覆盖)原则:

    1. 两同:方法名、参数列表相同
    2. 两小:子类方法返回值<=父类方法返回值
    3. 一大:子类方法访问权限>=父类方法访问权限

    23.当程序创建一个子类对象时,系统不仅会为该类中定义的实例变量分配内存,也会为它从父类继承得到的所有实例变量分配内存。

    24.引用变量类型:

    1. 编译时类型:由声明该变量时使用的类型决定
    2. 运行时类型:由实际赋给该变量的对象决定
    3. 编译时类型和运行时类型不同时,就出现了所谓的多态
    4. 引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法(可用强制类型转换解决问题)。

    25.向上转型:把一个子类对象直接赋值给父类引用变量;强制类型转换:把一个父类对象赋给子类引用变量

    26多态:

    1. 相同类型的变量,调用同一个方法时呈现出多种不同的行为特征叫做多态
    2. 成员变量不存在多态,总是调用父类的值

    27.instanceof:判断前面的对象是否是后面的类,或者其子类、实现类的实例

    String str="str";
    //true
    System.out.println(str instanceof Object);
    Object obj=new Object();
    //false
    System.out.println(obj instanceof String);

    28.继承与组合:

    1. 继承代表"is a",组合代表"has a"
    2. 创建子类对象,系统会为其父类所定义的实例变量分配内存空间,因此继承和组合在系统开销上没有太大的区别

    29.初始化块:

    1. 初始化块在构造器之前执行(编译后初始化块的内容会还原到构造器中)
    2. 静态初始化块在普通初始化块之前执行

    30.包装类:包装类的实例可以与数值类型直接比较

    31.toString:自定义类时,尽量重写类的toString方法,便于输出实例的值

    32.==与equals:

    1. 对于引用类型,只有二者指向同一个对象,==才会等于true 
    2. String类型情况如下,编译时确定的数据在常量池中,运行时生成的数据在堆内存中
        // s1直接引用常量池中的"疯狂Java"
            String s1 = "疯狂Java";
            String s2 = "疯狂";
            String s3 = "Java";
            // s4后面的字符串值可以在编译时就确定下来
            // s4直接引用常量池中的"疯狂Java"
            String s4 = "疯狂" + "Java";
            // s5后面的字符串值可以在编译时就确定下来
            // s5直接引用常量池中的"疯狂Java"
            String s5 = "疯" + "狂" + "Java";
            // s6后面的字符串值不能在编译时就确定下来,
            // 不能引用常量池中的字符串
            String s6 = s2 + s3;
            // 使用new调用构造器将会创建一个新的String对象,
            // s7引用堆内存中新创建的String对象
            String s7 = new String("疯狂Java");
            System.out.println(s1 == s4); // 输出true
            System.out.println(s1 == s5); // 输出true
            System.out.println(s1 == s6); // 输出false
            System.out.println(s1 == s7); // 输出false

    33.重写equals的条件:

    1. 自反性:x.equals(x)=true
    2. 对称性:若x.equals(y)=true,则y.equals(x)=true
    3. 传递性:若x.equals(y)=true,y.equals(z)=true,则x.equals(z)=true
    4. 一致性:只要x.equals(y)=true且x,y不变,无论调用多少次结果都不变
    5. 对任何不适Null的x,x.equals(null)=false 6.equals相同,则hashcode相同

    34.null类型的实例可以访问类的静态方法和静态变量,在底层是通过该实例的类去访问的

    35.final:

    1. final变量不是不能被赋值,而是不能被改变
    2. final变量必须由程序员显示的指定初始值
    3. final修饰引用变量时,引用地址不可以改变,对象可以改变
    4. final修饰的方式不能被重写,但是可以被重载

    36.宏变量:定义final变量时就为该变量指定了初始值,而且可以在编译时就确定下来,编译器会把程序中所有用到改变量的地方直接替换成该变量的值(进入常量池)

    37.不可变类:

    1. private final修饰所有成员变量
    2. 只有getter没有setter

    38.缓存池:先进先出缓存实例,重写了equals和hsahcode

    class CacheImmutale
    {
        private static int MAX_SIZE = 10;
        // 使用数组来缓存已有的实例
        private static CacheImmutale[] cache
            = new CacheImmutale[MAX_SIZE];
        // 记录缓存实例在缓存中的位置,cache[pos-1]是最新缓存的实例
        private static int pos = 0;
        private final String name;
        private CacheImmutale(String name)
        {
            this.name = name;
        }
        public String getName()
        {
            return name;
        }
        public static CacheImmutale valueOf(String name)
        {
            // 遍历已缓存的对象,
            for (int i = 0 ; i < MAX_SIZE; i++)
            {
                // 如果已有相同实例,直接返回该缓存的实例
                if (cache[i] != null
                    && cache[i].getName().equals(name))
                {
                    return cache[i];
                }
            }
            // 如果缓存池已满
            if (pos == MAX_SIZE)
            {
                // 把缓存的第一个对象覆盖,即把刚刚生成的对象放在缓存池的最开始位置。
                cache[0] = new CacheImmutale(name);
                // 把pos设为1
                pos = 1;
            }
            else
            {
                // 把新创建的对象缓存起来,pos加1
                cache[pos++] = new CacheImmutale(name);
            }
            return cache[pos - 1];
    
        }
        public boolean equals(Object obj)
        {
            if(this == obj)
            {
                return true;
            }
            if (obj != null && obj.getClass() == CacheImmutale.class)
            {
                CacheImmutale ci = (CacheImmutale)obj;
                return name.equals(ci.getName());
            }
            return false;
        }
        public int hashCode()
        {
            return name.hashCode();
        }
    }
    public class CacheImmutaleTest
    {
        public static void main(String[] args)
        {
            CacheImmutale c1 = CacheImmutale.valueOf("hello");
            CacheImmutale c2 = CacheImmutale.valueOf("hello");
            // 下面代码将输出true
            System.out.println(c1 == c2);
        }
    }

    39.默认方法:

    1. JDK1.8后新增的方法,在接口中一共有三种方法,抽象方法(abstract),类方法(static),默认方法(default),后两者必须有方法实现
    2. 使用接口的实例来调用默认方法

    40.抽象类:抽象类作为多个子类的抽象父类,可以被当成系统实现过程的中间产品,这个中间产品已经实现了系统的部分功能,但这个产品依然不能当成最终产品,必须由进一步的完善,

    41.内部类:

    1. 提供更好的封装
    2. 内部类成员可以直接访问外部类的私有数据
    3. 匿名内部类适用于创建只需要一次使用的类
    4. 局部内部类和匿名内部类不是类成员
    5. 包含内部类的类被称为外部类

    42.非静态内部类:

    1. 非静态内部类对象里保存了一个外部类的引用
    2. 外部类对象访问非静态内部类成员时,可能非静态普通内部类对象根本不存在
    3. 不允许在非静态内部类定义静态成员

    43.静态内部类:

    1. 静态内部类可以包含静态成员和非静态成员
    2. 静态内部类是外部类的类相关,静态内部类对象寄生在外部类的类本身中,只持有外部类的类引用,没有外部类的对象引用

    44.内部类的使用:

    1. 尽量使用静态内部类(调用简单)
    2. 局部内部类没有什么卵用 
    3. 非静态内部类的构造器必须由其外部类的对象来调用
    public class SubClass extends Out.In
    {
        //显示定义SubClass的构造器
        public SubClass(Out out)
        {
            //通过传入的Out对象显式调用In的构造器
            out.super("hello");
        }
    }

    45.匿名内部类:

    1. 必须继承一个父类或者实现一个接口
    2. 不能是抽象类
    3. 不能定义构造器
    4. JDK1.8以前被匿名内部类访问的局部变量必须使用final修饰,1.8以后会自动加上final修饰

    46.枚举类:可以使用枚举类来替代静态final常量

    public class Enum {
    public enum Season{
        spring,summer,fall,winter;
    }
    public static void main(String[] args) {
        Season season=Season.spring;
        System.out.println(season);
        switch (season){
        case spring:
            System.out.println("spring");
            break;
        case summer:
            System.out.println("summer");
            break;
        case fall:
            System.out.println("fall");
            break;
        case winter:
            System.out.println("winter");
            break;
        }
        
    }

    47.垃圾回收:

    1. 只负责回收对象,不负责物理资源
    2. 程序无法精确控制垃圾回收的运行
    3. 在回收对象前,会调用对象的finalize方法尝试让其获得新的引用以复活
    4. finalize方法何时被调用具有不确定性
    public class FinalizeTest
    {
        private static FinalizeTest ft = null;
        public void info()
        {
            System.out.println("测试资源清理的finalize方法");
        }
        public static void main(String[] args) throws Exception
        {
            // 创建FinalizeTest对象立即进入可恢复状态
            new FinalizeTest();
            // 通知系统进行资源回收
    //        System.gc();  //// 强制垃圾回收机制调用可恢复对象的finalize()方法
    //        Runtime.getRuntime().runFinalization();   //
            System.runFinalization();   //
            ft.info();
        }
        public void finalize()
        {
            // 让tf引用到试图回收的可恢复对象,即可恢复对象重新变成可达
            ft = this;
        }
    }

    48.引用类型:

    1. 强引用(最常见的引用)
    2. 软引用(当系统内存空间不够时会被回收)
    3. 弱引用(比软引用级别更低,当系统垃圾回收机制运行时,无论内存够不够都会被回收)
    4. 虚引用(没什么用)
  • 相关阅读:
    python基础-->流程控制-->分支结构-->单项分支-->双向分支
    python 控制语句基础---->代码块:以为冒号作为开始,用缩进来划分作用域,代表一个整体,是一个代码块,一个文件(模块)也称为一个代码块 | 作用域:作用的范围
    python基础语法
    Python Built-in Function 学习笔记
    身份证运算符 is 和 is not(检查两个数据在内存当中是否是同一个值) | 逻辑运算符 and or not | 数据类型的判断 isinstance
    算数运算符: +
    变量存储缓存机制 Number (int bool float complex)
    关于容器类型数据的强转一共:str() list() set() tuple() dict() 都可以转换成对应的数据类型 /Number 数据类型的强转一共: int() bool() flaot() complex() 都可以转换成对应的数据类型
    python 容器类型数据 (str list tuple set dict)
    Number 强制类型转换 int 强制转换整型 float 强制转换浮点型 complex 强制转换成复数 bool 强制转换成布尔类型,结果只有两种,要么True 要么 False """bool 可以转换所有的数据类型 everything"""
  • 原文地址:https://www.cnblogs.com/xx-wqj/p/5990301.html
Copyright © 2020-2023  润新知