java编程思想——初始化和清除

初始化和清除(1)

  1. java自动调用构造器以保证每个对象的初始化。
  2. 构造器方法的名字和类名一致。

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-01-20 9:52 AM
 */
class Rock {
    public Rock() {
        System.out.print("Rock ");
    }
}

public class SimpleConstructor {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Rock();
        }
    }
}

//输出:
//Rock Rock Rock Rock Rock Rock Rock Rock Rock Rock 

⚠️注意:构造器的名字必须与类名完全匹配
4. 默认构造器:没有参数的构造器
5. 构造器方法也可以有参数

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-01-20 10:03 AM
 */
public class SimpleConstructor2 {
    public static void main(String[] args) {
        for (int i = 0; i < 8; i++) {
            new Rock2(i);
        }
    }
}

class Rock2 {
    public Rock2(int i) {
        System.out.print("Rock " + i + " ");
    }
}

//输出结果
//Rock 0 Rock 1 Rock 2 Rock 3 Rock 4 Rock 5 Rock 6 Rock 7 
  1. 构造器参数提供了对象初始化的方式
  2. java中,创建和初始化是统一的概念。
  3. 构造器没有返回值。

初始化和清除(2)

  1. 方法重载:同样的方法名,参数不一样。

代码示例:

package initialization;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-01-20 10:59 AM
 */
public class Overloading {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            Tree t = new Tree(i);
            t.info();
            t.info("overloaded method");
        }
        new Tree();
    }
}

class Tree {
    int height;

    Tree() {
        print("Planting a seedling");
        height = 0;
    }

    public Tree(int initialHeight) {
        height = initialHeight;
        print("Creating new Tree that is " + height + " feet tall");
    }

    void info() {
        print("Tree is " + height + " feet tall");
    }

    void info(String s) {
        print(s + ": Tree is " + height + " feet tall");
    }
}
//输出结果
//Creating new Tree that is 0 feet tall
//Tree is 0 feet tall
//overloaded method: Tree is 0 feet tall
//Creating new Tree that is 1 feet tall
//Tree is 1 feet tall
//overloaded method: Tree is 1 feet tall
//Creating new Tree that is 2 feet tall
//Tree is 2 feet tall
//overloaded method: Tree is 2 feet tall
//Creating new Tree that is 3 feet tall
//Tree is 3 feet tall
//overloaded method: Tree is 3 feet tall
//Creating new Tree that is 4 feet tall
//Tree is 4 feet tall
//overloaded method: Tree is 4 feet tall
//Planting a seedling

  1. 原型和方法重载结合使用:
    • 整数值被定义为int
    • 如果数据类型小于方法参数类型,数据类型会被提升
    • char如果找不到匹配方法,则会提升为int
package initialization;

import static net.mindview.util.Print.print;
import static net.mindview.util.Print.printnb;

/**
 * @author vincient
 * @create 2020-01-20 11:26 AM
 */
public class PrimitiveOverloading {
    void f1(char x) {
        printnb("f1(char) ");
    }

    void f1(byte x) {
        printnb("f1(byte) ");
    }

    void f1(short x) {
        printnb("f1(short) ");
    }

    void f1(int x) {
        printnb("f1(int) ");
    }

    void f1(long x) {
        printnb("f1(long) ");
    }

    void f1(float x) {
        printnb("f1(float) ");
    }

    void f1(double x) {
        printnb("f1(double) ");
    }

    void f2(byte x) {
        printnb("f2(byte) ");
    }

    void f2(short x) {
        printnb("f2(short) ");
    }

    void f2(int x) {
        printnb("f2(int) ");
    }

    void f2(long x) {
        printnb("f2(long) ");
    }

    void f2(float x) {
        printnb("f2(float) ");
    }

    void f2(double x) {
        printnb("f2(double) ");
    }

    void f3(short x) {
        printnb("f3(short) ");
    }

    void f3(int x) {
        printnb("f3(int) ");
    }

    void f3(long x) {
        printnb("f3(long) ");
    }

    void f3(float x) {
        printnb("f3(float) ");
    }

    void f3(double x) {
        printnb("f3(double) ");
    }

    void f4(int x) {
        printnb("f4(int) ");
    }

    void f4(long x) {
        printnb("f4(long) ");
    }

    void f4(float x) {
        printnb("f4(float) ");
    }

    void f4(double x) {
        printnb("f4(double) ");
    }

    void f5(long x) {
        printnb("f5(long) ");
    }

    void f5(float x) {
        printnb("f5(float) ");
    }

    void f5(double x) {
        printnb("f5(double) ");
    }

    void f6(float x) {
        printnb("f6(float) ");
    }

    void f6(double x) {
        printnb("f6(double) ");
    }

    void f7(double x) {
        printnb("f7(double) ");
    }

    void testConstVal() {
        printnb("5: ");
        f1(5);
        f2(5);
        f3(5);
        f4(5);
        f5(5);
        f6(5);
        f7(5);
        print();
    }

    void testChar() {
        char x = 'x';
        printnb("char: ");
        f1(x);
        f2(x);
        f3(x);
        f4(x);
        f5(x);
        f6(x);
        f7(x);
        print();
    }

    void testByte() {
        byte x = 0;
        printnb("byte: ");
        f1(x);
        f2(x);
        f3(x);
        f4(x);
        f5(x);
        f6(x);
        f7(x);
        print();
    }

    void testShort() {
        short x = 0;
        printnb("short: ");
        f1(x);
        f2(x);
        f3(x);
        f4(x);
        f5(x);
        f6(x);
        f7(x);
        print();
    }

    void testInt() {
        int x = 0;
        printnb("int: ");
        f1(x);
        f2(x);
        f3(x);
        f4(x);
        f5(x);
        f6(x);
        f7(x);
        print();
    }

    void testLong() {
        long x = 0;
        printnb("long: ");
        f1(x);
        f2(x);
        f3(x);
        f4(x);
        f5(x);
        f6(x);
        f7(x);
        print();
    }

    void testFloat() {
        float x = 0;
        printnb("float: ");
        f1(x);
        f2(x);
        f3(x);
        f4(x);
        f5(x);
        f6(x);
        f7(x);
        print();
    }

    void testDouble() {
        double x = 0;
        printnb("double: ");
        f1(x);
        f2(x);
        f3(x);
        f4(x);
        f5(x);
        f6(x);
        f7(x);
        print();
    }

    public static void main(String[] args) {
        PrimitiveOverloading p = new PrimitiveOverloading();
        p.testConstVal();
        p.testChar();
        p.testByte();
        p.testShort();
        p.testInt();
        p.testLong();
        p.testFloat();
        p.testDouble();
    }
}
//输出结果
//5: f1(int) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double)
//char: f1(char) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double)
//byte: f1(byte) f2(byte) f3(short) f4(int) f5(long) f6(float) f7(double)
//short: f1(short) f2(short) f3(short) f4(int) f5(long) f6(float) f7(double)
//int: f1(int) f2(int) f3(int) f4(int) f5(long) f6(float) f7(double)
//long: f1(long) f2(long) f3(long) f4(long) f5(long) f6(float) f7(double)
//float: f1(float) f2(float) f3(float) f4(float) f5(float) f6(float) f7(double)
//double: f1(double) f2(double) f3(double) f4(double) f5(double) f6(double) f7(double) 
  1. 如果参数超过方法参数的范围,需要对参数进行窄化操作

代码示例:

package initialization;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-01-20 2:10 PM
 */
public class Demotion {
    void f1(char x) {
        print("f1(char)");
    }

    void f1(byte x) {
        print("f1(byte)");
    }

    void f1(short x) {
        print("f1(short)");
    }

    void f1(int x) {
        print("f1(int)");
    }

    void f1(long x) {
        print("f1(long)");
    }

    void f1(float x) {
        print("f1(float)");
    }

    void f1(double x) {
        print("f1(double)");
    }

    void f2(char x) {
        print("f2(char)");
    }

    void f2(byte x) {
        print("f2(byte)");
    }

    void f2(short x) {
        print("f2(short)");
    }

    void f2(int x) {
        print("f2(int)");
    }

    void f2(long x) {
        print("f2(long)");
    }

    void f2(float x) {
        print("f2(float)");
    }

    void f3(char x) {
        print("f3(char)");
    }

    void f3(byte x) {
        print("f3(byte)");
    }

    void f3(short x) {
        print("f3(short)");
    }

    void f3(int x) {
        print("f3(int)");
    }

    void f3(long x) {
        print("f3(long)");
    }

    void f4(char x) {
        print("f4(char)");
    }

    void f4(byte x) {
        print("f4(byte)");
    }

    void f4(short x) {
        print("f4(short)");
    }

    void f4(int x) {
        print("f4(int)");
    }

    void f5(char x) {
        print("f5(char)");
    }

    void f5(byte x) {
        print("f5(byte)");
    }

    void f5(short x) {
        print("f5(short)");
    }

    void f6(char x) {
        print("f6(char)");
    }

    void f6(byte x) {
        print("f6(byte)");
    }

    void f7(char x) {
        print("f7(char)");
    }

    void testDouble() {
        double x = 0;
        print("double argument:");
        f1(x);
        f2((float) x);
        f3((long) x);
        f4((int) x);
        f5((short) x);
        f6((byte) x);
        f7((char) x);
    }

    public static void main(String[] args) {
        Demotion p = new Demotion();
        p.testDouble();
    }
}

//执行结果:
//double argument:
//f1(double)
//f2(float)
//f3(long)
//f4(int)
//f5(short)
//f6(byte)
//f7(char)
  1. 不能通过返回值类型来区分重载方法

初始化和清除(3)

  1. 默认构造器没有参数,用于创建默认对象。
  2. 如果类里面没有构造器,编译器会自动创建一个默认构造器。

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-01-20 2:30 PM
 */
public class DefaultConstructor {
    public static void main(String[] args) {
        Bird b = new Bird();
    }
}

class Bird{

}
  1. 如果自定义了构造器,编译器就不会生成构造器了。

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-01-20 2:35 PM
 */
public class NoSynthesis {
    public static void main(String[] args) {
        //! Bird2 b = new Bird2(); // No default 
        Bird2 b2 = new Bird2(1);
        Bird2 b3 = new Bird2(1.0);
    }
}

class Bird2 {
    public Bird2(int i) {
    }

    public Bird2(double d) {
    }
}

初始化和清除(4)

  1. 调用方法时,编译器将对象的引用作为第一个参数隐式传递给方法。***this***对应这个引用。
  2. ***this***只能在非静态方法中被调用
  3. 如果在一个方法内部调用同一类的其他方法,不需要使用***this***,直接调用方法即可。***this***被自动用于这些方法调用上了。
  4. **this通常用于return语句中。

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-01-20 3:23 PM
 */
public class Leaf {
    int i = 0;

    Leaf increament() {
        i++;
        return this;
    }

    void print() {
        System.out.println("i = " + i);
    }

    public static void main(String[] args) {
        Leaf x = new Leaf();
        x.increament().increament().increament().print();
    }
}

//输出结果:
//i = 3
  1. ***this***被用于将当前对象传递倒别的方法中

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-01-20 3:31 PM
 */
public class PassingThis {
    public static void main(String[] args) {
        new Person().eat(new Apple());
    }
}


class Person {
    public void eat(Apple apple) {
        Apple peeled = apple.getPeeled();
        System.out.println("Yummy");
    }
}

class Peeler {
    static Apple peel(Apple apple) {
        // ... remove peel
        return apple;
    }
}

class Apple {
    Apple getPeeled() {
        return Peeler.peel(this);
    }
}

//输出结果
//Yummy

⚠️外部工具方法是保证代码跨对象使用并减少重复代码

  1. 从构造器中调用构造器,可以使用***this***,以减少重复代码。
  2. 在构造器中使用***this***外加参数列表,可以调用匹配的构造器。
package initialization;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-01-20 4:05 PM
 */
public class Flower {
    int petalCount = 0;
    String s = "initial value";

    public Flower(int petals) {
        petalCount = petals;
        print("Constructor w/ int arg only, petalCount= " + petalCount);
    }

    public Flower(String ss) {
        print("Constructor w/ String arg only, s = " + ss);
        s = ss;
    }

    public Flower(String s, int petals) {
        this(petals);
//        this(s);
        this.s = s;
        print("String & int args");
    }

    public Flower() {
        this("hi", 47);
        print("default constructor (no args)");
    }

    void printPetalCount() {
//        this(11);
        print("petalCount = " + petalCount + " s = " + s);
    }

    public static void main(String[] args) {
        Flower x = new Flower();
        x.printPetalCount();
    }
}

//运行结果:
//Constructor w/ int arg only, petalCount= 47
//String & int args
//default constructor (no args)
//petalCount = 47 s = hi

⚠️只能在构造器中调用一次this***,构造器调用必须一开始就调用。
8. 当成员数据名和参数名一致时,使用this以表明对成员数据的调用。
9. 不可在其他成员方法中调用构造器方法。
10. static特点:
- static方法中不可使用
this

- static方法中不可调用
non-static方法
- non-static方法可以调用static方法
- 可以直接使用类调用
static*方法
- static方法可以访问其他的静态方法和静态字段


初始化和清除(5)

  1. java的垃圾回收器会回收并恢复不再使用的对象的内存
  2. gc只会释放使用new分配的内存,不会释放其他方式生成的内存。为了处理这种情况,java提供了可自定义的finalize方法。
  3. finalize方法的工作机制:当gc准备释放对象的内存时将首先调用finalize方法,并在下一次垃圾回收时回收并释放对象内存。
  4. finalize和C++中的destructor的区别:
    • 对象不一定被垃圾回收
    • 垃圾回收不是销毁
  5. 垃圾回收是有开销的
  6. finalize并不是通用意义上的清除方法。
  7. 垃圾回收只和内存相关,它唯一存在的理由就是恢复程序不再使用的内存
  8. finalize方法只与内存及其回收相关。
  9. 垃圾回收只关心如何释放对象,不关心对象如何创建,finalize的使用仅限于特殊的内存分配场合。之所以使用finalize方法是因为在分配内存时使用了类似C语言的做法,主要通过调用native methodsnative methods使用malloc函数分配内存,除非调用free函数进行释放。finalize方法会调用free函数。

结论:finalize并不适合进行java的常规清除操作

  1. 清除的难题:在需要清除的时候进行清除。但是这个理念在’C++'的destructor的理念中是有冲突的。在C++中,所有的对象都应该被清除。如果是局部对象,那么就应该对象创建的花括号里面进行清除。如果是使用new创建的对象,就应该使用delete()进行释放。这会导致难以跟踪的问题。
  2. java不允许创建局部对象(对象不允许存放在栈中)。对象都是通过new创建的。而gc正好可以用来回收内存。所以java中没有destructor。但是为了满足需求,有时需要编写一些类似destructor的方法,用来调用并释放内存。
  3. 终结条件:在对象回收时发现未合理清除的部分。

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-01-21 11:27 AM
 */
public class TerminationCondition {
    public static void main(String[] args) {
        Book novel = new Book(true);
        novel.checkIn();
        new Book(true);
        System.gc();
    }

}


class Book {
    boolean checkedOut = false;

    public Book(boolean checkOut) {
        checkedOut = checkOut;
    }

    void checkIn() {
        checkedOut = false;
    }

    @Override
    protected void finalize() throws Throwable {
        if (checkedOut) {
            System.out.println("Error: checked out");
            super.finalize();
        }
    }
}

//运行结果
//Error: checked out
  1. JVM的堆有堆指针,这样内存分配会更快。垃圾回收会将废弃的对象内存回收后。会压缩堆里面所有的对象。避免分页错误。
  2. 垃圾回收的实现方式
    • 引用计数(简单但是缓慢)
    • 对象引用链
    • jvm采用自适应型的垃圾回收策略。
      • stop-and-copy
      • mark-and-sweep

结论:JVM会根据实际情况选用相关的垃圾回收策略
15. 其他提高JVM执行效率的方式:
- JIT编译器:将程序编译成本地机器码,缺点是代码在编译时需要时间,同时增大程序体量,导致内存分页,最终降低程序运行效率。
- 替代完全JIT的方式,使用lazy-evaluation方式。现有方案Java HotSpot technologies


初始化和清除(6)

  1. java尽量保证变量初始化
    • 方法变量必须有初始化值
    • 字段会自动获得默认值,如果是对象,得到的默认值为null
  2. 可以在定义变量的时候给变量赋初始化值
  3. 可以使用方法初始化变量,方法也可以使用参数,但是方法使用的参数不能是尚未初始化的字段。

初始化和清除(7)

  1. 构造器初始化,使初始化更加灵活,但在进入构造器方法之前,自动初始化就已经执行了。
  2. 初始化的顺序:初始化的顺序取决于类中变量的定义顺序。在所有方法调用之前,变量就已经初始化了。

代码示例:

package initialization;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-02-02 2:14 PM
 */
public class OrderOfInitialization {
    public static void main(String[] args) {
        House h = new House();
        h.f();
    }
}

class Window {
    public Window(int marker) {
        print("Window(" + marker + ")");
    }
}

class House {
    Window w1 = new Window(1);

    public House() {
        print("House()");
        w3 = new Window(33);
    }

    Window w2 = new Window(2);

    void f() {
        print("f()");
    }

    Window w3 = new Window(3);
}
//运行结果
//Window(1)
//Window(2)
//Window(3)
//House()
//Window(33)
//f()
  1. 静态数据初始化:static区域只有同一块内存,不管创建了多少对象。static不适用于局部变量。

代码示例:

package initialization;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-02-02 2:35 PM
 */
public class StaticInitialization {
    public static void main(String[] args) {
        print("Creating new Cupboard() in main");
        new Cupboard();
        print("Creating new Cupboard() in main");
        new Cupboard();
        table.f2(1);
        cupboard.f3(1);
    }

    static Table table = new Table();
    static Cupboard cupboard = new Cupboard();
}

class Bowl {
    public Bowl(int marker) {
        print("Bowl(" + marker + ")");
    }

    void f1(int marker) {
        print("f1(" + marker + ")");
    }
}

class Table {
    static Bowl bowl1 = new Bowl(1);

    public Table() {
        print("Table()");
        bowl2.f1(1);
    }

    void f2(int marker) {
        print("f2(" + marker + ")");
    }

    static Bowl bowl2 = new Bowl(2);
}

class Cupboard {
    Bowl bowl3 = new Bowl(3);
    static Bowl bowl4 = new Bowl(4);

    public Cupboard() {
        print("Cupboard()");
        bowl4.f1(2);
    }

    void f3(int marker) {
        print("f3(" + marker + ")");
    }

    static Bowl bowl5 = new Bowl(5);
}

//执行结果:
//Bowl(1)
//Bowl(2)
//Table()
//f1(1)
//Bowl(4)
//Bowl(5)
//Bowl(3)
//Cupboard()
//f1(2)
//Creating new Cupboard() in main
//Bowl(3)
//Cupboard()
//f1(2)
//Creating new Cupboard() in main
//Bowl(3)
//Cupboard()
//f1(2)
//f2(1)
//f3(1)
  1. static变量的初始化只在需要的时候进行。当第一个对象创建的时候执行初始化。
  2. 变量的初始化顺序是先static后非static
  3. 显式的静态初始化:java使用static语句块将静态初始化包含起来。
  4. 非静态实例初始化:和静态初始化类似,除了没有static

初始化和清除(8)

  1. 数组的定义:在类型后加上[],也可以在标识之后加[]
  2. 数组的初始化,可以使用特殊语法,如:
int[] a1 = { 1, 2, 3, 4, 5 };
  1. 数组的基本成员量:length
  2. 如果在编写代码时不知道数组里有多少元素,可以使用new来生成数组中的元素,例如:
import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-02-03 11:13 AM
 */
public class ArrayNew {
    public static void main(String[] args) {
        int[] a;
        Random random = new Random(47);
        a = new int[random.nextInt(20)];
        print("length of a = " + a.length);
        print(Arrays.toString(a));
    }
}

//运行结果
//length of a = 18
//[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  1. 数组元素会默认初始化为零值。
  2. 可变参数列表,代码示例:
package initialization;

/**
 * @author vincient
 * @create 2020-02-03 1:18 PM
 */
public class VarArgs {
    static void printArray(Object[] args) {
        for (Object obj : args) {
            System.out.print(obj + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        printArray(new Object[]{new Integer(47), new Float(3.14), new Double(11.11)});
        printArray(new Object[]{"one", "two", "three"});
        printArray(new Object[]{new A(), new A(), new A()});
    }
}

class A {

}
//运行结果
//47 3.14 11.11
//one two three
//initialization.A@511d50c0 initialization.A@60e53b93 initialization.A@5e2de80c 
  1. java SE5引入新的可变参数列表特性写法:…
  2. 使用可变参数需要避免重载出现冲突,通常应当对某个版本的重载方法使用可变参数列表

初始化和清除(9)

  1. Java SE5新增关键词:enmu
  2. 枚举的每个实例都是常量,所以都是大写。

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-02-03 2:41 PM
 */
public enum Spiciness {
    NOT, MILD, MEDIUM, HOT, FLAMING
}
  1. Enum有各种内置方法:toString(),ordinal(),values()

代码示例:

package initialization;

/**
 * @author vincient
 * @create 2020-02-03 2:49 PM
 */
public class EnumOrder {
    public static void main(String[] args) {
        for (Spiciness s : Spiciness.values()) {
            System.out.println(s + ", ordinal " + s.ordinal());
        }
    }
}
//运行结果
//NOT, ordinal 0
//MILD, ordinal 1
//MEDIUM, ordinal 2
//HOT, ordinal 3
//FLAMING, ordinal 4
  1. enum可以用于switch语句中,代码示例:
package initialization;

/**
 * @author vincient
 * @create 2020-02-03 2:51 PM
 */
public class Burrito {
    Spiciness degree;

    public Burrito(Spiciness degree) {
        this.degree = degree;
    }

    public void describe() {
        System.out.print("This burrito is ");
        switch (degree) {
            case NOT:
                System.out.println("not spicy at all.");
                break;
            case MILD:
            case MEDIUM:
                System.out.println("a little hot.");
                break;
            case HOT:
            case FLAMING:
            default:
                System.out.println("maybe too hot.");
        }
    }

    public static void main(String[] args) {
        Burrito
                plain = new Burrito(Spiciness.NOT),
                greenChile = new Burrito(Spiciness.MEDIUM),
                jalapeno = new Burrito(Spiciness.HOT);
        plain.describe();
        greenChile.describe();
        jalapeno.describe();
    }
}
//运行结果
//This burrito is not spicy at all.
//This burrito is a little hot.
//This burrito is maybe too hot.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值