一、初读java编程思想前四章

来源:互联网 发布:易云网络 西安 编辑:程序博客网 时间:2024/06/08 12:30

1、前四章都是比较基础的东西,所以看的较快,要敲的代码也不多,所以整理在一起吧。


2、第一章:对象导论

  • OOP:面向对象编程 Object-oriented Programming

  • private:除类型创建者和类型的内部方法之外的任何人都不可以访问的元素

  • protected:基本同protected,但是它的子类是可以访问protected的,但是不能访问private
  • public:都可以看
  • 默认:被称为包访问权限,类可以访问在同一个包下的其他类的成员

  • 继承初识:继承中存在两种关系:“是一个”和“像是一个”

    • “是一个”,即“is a”,表示纯粹的继承,子类与父类方法完全相同,子类只是单纯地重写一下。
    • “像是一个”,即“is like a”,表示对父类进行扩展了。
    • 儿子与父亲,儿子继承父亲,两个类光溜溜啥都不写或者只写默认构造器,new一下儿子,先执行父亲的默认构造器,再执行儿子的默认构造器。
    • 如果父亲只写了有参构造器,没有写默认构造器,在儿子的构造器中,是必须显式声明调用的是有参的构造器:super(xxx参数)才行,否则会编译不通过
    • 如果父亲中默认构造器和有参构造器都写了,儿子构造器中就不需要显式地声明了,也就是说,这个时候儿子默认会调用父亲的默认构造器。
    • 如果父亲中默认构造器和有参构造器都有,并且在默认构造器中庸this(xxx参数)调用有参构造器,执行顺序肯定是先执行父亲的有参构造器,然后执行父亲的默认构造器,最后再执行儿子自己的。顺序同上。
    • 如果必须要显示地声明,那么必须写在儿子构造器的第一行,否则编译不通过。
    • java中是单继承,最终都继承于Object这个基类。
  • 多态初识

    • 简而言之,就是父类变量指向子类对象。
    • 假设儿子继承父亲,在父亲中比如有某个方法是跳舞,那么子类继承覆盖。这个时候我们可以这样:

      Father father;Son son = new Son();father = son;//父类变量指向子类对象son.dance();father.dance();

      这样的话,结果都是儿子在跳舞了。

    • 这样的实现是在运行时才能决定究竟是用的什么子类对象,即后期绑定。
    • 动态绑定,就是以上内容的一个升级,按照书上的例子:
    //写了一个形状的基类public class Shape {    public void draw(){        System.out.println("我是基类,我天生会画画");    }}//写了一个圆形类,他是形状的子类public class Circle extends Shape{    @Override    public void draw() {    System.out.println("我是圆形,我是形状,所以我也会画画!'");    }}//写了一条线的类,他也是形状的子类public class Line extends Shape{    @Override    public void draw() {        System.out.println("我是一条线,我也是形状,所以我天生会画画");    }}//最后主函数实现动态绑定的演示public class Main {    public static void dosomething(Shape shape){        shape.draw();    }    public static void main(String[] args) {        dosomething(new Circle());//我是圆形,我是形状,所以我也会画画!'        dosomething(new Line());//我是一条线,我也是形状,所以我天生会画画    }}
    • 这就是所谓的向上转型,是安全的。当然,也可以向下,但是存在风险,因为父类不一定是子类的实例化对象,即编写程序的时候,比如(Object)直接赋给子类是不会报错的,但是运行时会报错,所以需要用instanceof先判断一下这个父类究竟是不是是子类的实例。
  • 初识集合

    • java提供的用来存储数据的数据结构
    • ArrayList和LinkedList两种的区别,前者是数组的数据结构,所以查找成本是相同的,但是插入和删除数据的代价比较大;后者是链表的数据结构,所以插入和查找的成本比较低,但是查询数据成本高,尤其当这个数据处于链表的末尾。
  • 初识泛型

    • 在使用上述集合的时候,我们需要规定一下放入的参数究竟是什么类型的,省去了很多麻烦。这就是泛型的威力,
  • 对象的创建和生命期

    • java完全采用动态分配内存,用new就可以创建了。所谓的动态创建的含义是:直到运行时才知道需要多少对象,他们的生命周期如何,具体类型是什么。当需要一个新对象,可以在需要的时刻直接在堆中创建,因为存储空间是在运行时被动态管理的,所以需要大量的时间在堆中分配存储空间,这可以要远远大于在堆栈中创建存储空间的时间。在堆栈中创建存储空间和释放存储空间通常各需要一条汇编指令即可,分别对应将栈顶指针向下移动和将栈顶指针向上移动。
    • 对象趋于复杂,所以查找和释放存储空间的开销不会对对象的创建造成重大冲击。
    • 关于堆上的对象生命周期,编译器是一无所知的,java提供了“垃圾回收器”的机制,他可以自动发现对象何时不再被使用,并继而销毁他。可以避免暗藏的内存泄露问题。
    • java只能以一种方式创建对象,即在堆上创建。
  • 初识异常

    • 任何程序都要处理错误,java为我们提供了异常的机制,异常不能被忽略,通过这种强制性的要求,保证程序的健壮性。
  • 初识并发编程

    • 一个问题被切分为很多独立运行的任务,这每个独立运行的任务被成为线程。
    • 线程只是一种为单一处理器分配执行时间的手段。如果是多处理器,那么就是真正地并行执行。
    • 由于程序在逻辑上被分为线程,所以如果机器拥有多个处理器,那么程序不需要特殊调整也能执行地更快。
    • 由于所有线程会共同访问呢一个共享资源,所以为了防止多个线程打架造成数据混乱,需要锁,使得有序地使用资源。

3、第二章:一切都是对象

  • 几种存储的方式

    • 寄存器:最快,处理器内部,但是数量有限,程序员不能直接控制。
    • 堆栈:位于通用RAM(随机只读存储器),但通过堆栈指针可以从处理器那里获得直接支持,堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。效率仅次于寄存器。对象的引用存在堆栈中,但是对象是存在堆上的。
    • 堆:一种通用的内存池(也位于RAM区),用于存放所有的java对象。不同于堆栈的地方是:编译器不需要知道存储的数据在堆里存活多长时间。具有很大的灵活性。灵活性的代价就是存储分配和清理需要更多的时间(相对于堆栈)。
    • 常量存储:直接存放在程序代码内部。这样做安全,并且永远不会被改变。
    • 非RAM存储:流对象直接发送到另一个机器,持久化对象被放到硬盘。支持持久化。
  • 基本类型

    基本类型 | 大小 | 大小---|--- | ---byte | 1个字节| 8 bitsshort | 2个字节 | 16bitsint | 4个字节 | 32bitslong | 8个字节 | 64 bitsfloat | 4个字节 | 32bitsdouble | 8个字节 | 64bitschar | 2个字节 | 16 bitsboolean | 不确定 | 不确定
  • 高精度数字

    • BigInteger
    • BigDecimal
    • 都没有对应的基本类型,但是与int 和 float 的操作是一样的。区别就是他是调用方法而已。由于这么做复杂了很多,所以运算速度会比较慢。在这里,用速度换精度。
  • 数组

    • java中数组确保会被初始化,但是一少量的内存开销和运行时的小标检查为代价,但是代价也是值得的。
    • 当创建一个数组,其实是创建了一个引用数组,并且每个引用会被自动初始化为一个特定值,该值拥有自己的关键字null,一旦java看到null,就知道这个引用还没有指向某个对象,运行时会报错。
    • 还可以创建用来存放基本数据类型的数组,编译器也能保证这种数组的初始化,因为呀会将这种数组所占的内存全部置零。比如 int[] array = new int[10];
  • java作用域

    • new 一个java对象时,它可以存活于作用域之外。
    • 由new创建的对象,只要你需要,就会一直保留下去。
  • - 类中的属性叫成员变量,不同于普通局部变量的是,即使没有进行初始化,java也会确保他获得一个默认值。默认值如下:

    基本类型 | 默认值---|---byte | (byte)0short | (short)0int | 0long | 0Lfloat | 0.0fdouble | 0.0dchar | nullboolean | false
  • static关键字

    • 将变量或者方法上升为类级别,不要跟随对象才能使用。即编译的时候就会存在了。

3、第三章:操作符

  • 赋值

    • 常量赋值就没什么可说的了。
    • 对象赋值,情况却变得特殊一点了。我们操作的不是对象本身,而是对象的引用。也就是说,是将“引用”从一个地方复制到另一个地方。下面利用书上的例子进行佐证一下。

    - 先定义一个简单的类:

    ```public class Tank {    public int level;}```

    - 然后主函数中:

    ```public class Main {    public static void main(String[] args) {        Tank t1 = new Tank();        Tank t2 = new Tank();        t1.level = 10;        t2.level = 20;        System.out.println("t1.level="+t1.level+",t2.level="+t2.level);        t1 = t2;        System.out.println("t1.level="+t1.level+",t2.level="+t2.level);        t1.level = 30;        System.out.println("t1.level="+t1.level+",t2.level="+t2.level);    }}//t1.level=10,t2.level=20//t1.level=20,t2.level=20//t1.level=30,t2.level=30```
    • 这就是“别名现象”,下面还有一个引用传递的例子,将上例的主函数修改一下:

    - 传递不是对象的副本,而是引用:

    ```public class Main {    static void f(Tank t){        t.level = 20;    }    public static void main(String[] args) {        Tank tank = new Tank();        tank.level = 10;        System.out.println("tank.level="+tank.level);//10        f(tank);        System.out.println("tank.level="+tank.level);//20    }}```
  • 一元加减操作符:

    • 一元减号-用于转变数据
    • 一元加号+只是为了与一元减号相对应,它唯一的作用仅仅是将较小类型的操作数提升为int.
  • 关系操作符

    • “==”就是直接比较引用,即地址,只要是两个new出来的,一定是不相等的。
    • “equals()”,默认情况下,等同于“==”,但是在String,Integer等封装类中已经重写了它,使得它比较的是内容是否相等。
  • 逻辑操作符

    • “&&” 具有短路的功能
  • 类型转换

    • 窄化转换:大的东西放进小桶里,不一定装得下,所以是危险的,需要进行强制类型转换,因为可能会丢失精度。
    • 扩展转换:小东西放进大桶里,一定装得下,所以不需要强制转换就可以实现转换了。
    • java允许除了boolean类型都可以进行互相转换。
  • 4、第四章:控制执行流程

    • true 、 false
    • if–else–elseif
    • while 、 do while 、 for 、foreach (while(true)和for(;;)是一样的,都是无穷循环)
    • return
    • break:退出当前循环
    • continue:结束当前迭代,退回循环开始处再进行下一次迭代(简而言之,就是当前循环到这一句卡住,下面的东西不执行,直接进行下一次循环了)

    - break和continue的小例子:

    ```public class Main {    public static void main(String[] args) {        for(int i = 0; i < 100; i++){            if(i == 74)                break;            if(i % 9 != 0)                continue;            System.out.print(i + " ");        }        System.out.println();        System.out.println("-----------------------");        int i = 0;        while(true){            i++;            int j = i * 27;            if(j == 1269)                break;            if(i % 10 != 0)                continue;            System.out.print(i + " ");        }    }}//output://0 9 18 27 36 45 54 63 72 //-----------------------//10 20 30 40 ```
    • goto : goto是java中的一个保留字,但在语言中并摸眼使用;java没有goto;但是java也可以完成一些类似于跳转的操作,与break和continue有关;他们其实不是一个跳转,而是中断迭代语句的一个方法。使用了标签这个机制。

    • label1:    outer-iteration{        inner-iteration{            //...            break;            //...            continue;            //...            continue label1;            //...            break label1;        }    }
    • break中断内部迭代,回到外部迭代。
    • continue使执行点移回内部迭代的起始处。
    • continue label1:同时中断内部迭代和外部迭代,直接转到label1处,随后,实际上是继续执行迭代过程,只是从外部迭代开始。
    • break label1:也会中断所有迭代,并回到label1处,但并不重新进入迭代。也就是说,他实际上完全终止了两个迭代。
    • 感觉好像没用过。暂时先了解一下吧。
    • swith
  • 斐波拉契序列:

public class Main {    public static int fib(int i){        if(i == 0){            return 0;        }else if(i == 1){            return 1;        }else {            return fib(i-1)+fib(i-2);        }    }    public static void main(String[] args) {        for(int i=0; i<=5; i++){            System.out.printf("Fibonacci of %d is: %d\n",                    i, fib(i));        }    }}

output is:

Fibonacci of 0 is: 0Fibonacci of 1 is: 1Fibonacci of 2 is: 1Fibonacci of 3 is: 2Fibonacci of 4 is: 3Fibonacci of 5 is: 5
  • 吸血鬼数字:
public class Main {    private static void method3() { // 官方参考答案        int[] startDigit = new int[4];        int[] productDigit = new int[4];        for (int num1 = 10; num1 <= 99; num1++)            for (int num2 = num1; num2 <= 99; num2++) {                // Pete Hartley's theoretical result:                // If x·y is a vampire number then                // x·y == x+y (mod 9)                if ((num1 * num2) % 9 != (num1 + num2) % 9)                    continue;                int product = num1 * num2;                startDigit[0] = num1 / 10;                startDigit[1] = num1 % 10;                startDigit[2] = num2 / 10;                startDigit[3] = num2 % 10;                productDigit[0] = product / 1000;                productDigit[1] = (product % 1000) / 100;                productDigit[2] = product % 1000 % 100 / 10;                productDigit[3] = product % 1000 % 100 % 10;                int count = 0;                for (int x = 0; x < 4; x++)                    for (int y = 0; y < 4; y++) {                        if (productDigit[x] == startDigit[y]) {                            count++;                            productDigit[x] = -1;                            startDigit[y] = -2;                            if (count == 4)                                System.out.println(num1 + " * " + num2 + " : "                                        + product);                        }                    }            } /*               * Output: 15 * 93 : 1395 21 * 60 : 1260 21 * 87 : 1827 27 * 81 :               * 2187 30 * 51 : 1530 35 * 41 : 1435 80 * 86 : 6880               *///:~    }    public static void main(String[] args) {        method3();    }}

output is:

21 * 60 : 126021 * 87 : 182727 * 81 : 218730 * 51 : 153035 * 41 : 143580 * 86 : 6880
原创粉丝点击