java编程思想

文章目录


基础知识

数据类型

整型
类型 存储空间
int 4字节
short 2字节
long 8字节
byte 1字节

byte 的取值范围是-128~127。整型的取值范围和运行 Java 代码的机器无关。Java 没有无符号的整型。

数据类型表示:

长整型:400L

十六进制:0xCA

八进制:020(有前缀0)

二进制:0b1001(Java 7及以上版本)

从 Java 7开始,可以为数据字面量添加下划线,如1_000_000,方便易读。Java 编译器会去除这些下划线。

浮点类型
类型 存储空间
float 4字节
double 8字节

float 类型的数值会有后缀 F 或者 f (2.01F),没有后缀 F 的浮点数默认为 double 类型(也可以加后缀 D)。浮点数采用二进制系统表示,有些数值会有精度损失,如System.out.println(2.0 - 1.1)会输出0.8999999999999999。如果数值计算不允许有任何精度误差,应该使用 BigDecimal。

特殊值

正无穷大:Double.POSITIVE_INFINITY

负无穷大:Double.NEGATIVE_INFINITY

NaN(不是一个数字):Double.NaN

char 类型

Unicode 字符用一个或者两个 char 值描述。Unicode 字符可以表示为十六进制,其范围从/u0000到/uffff。

boolean 类型

布尔类型有两个值:true 和 false。布尔型和整型不能相互转化。Java 语言表达式所操作的 boolean 值,在编译之后都使用Java虚拟机中的int数据类型来代替,而 boolean 数组将会被编码成 Java 虚拟机的 byte 数组,每个元素 boolean 元素占8位”。这样我们可以得出 boolean 类型占了单独使用是4个字节,在数组中又是1个字节。

大数值

BigInteger 实现了任意精度的整数运算,BigDecimal 实现了任意精度的浮点数运算。

BigInteger a = BigInteger.valueOf(100);
BigInteger b = BigInteger.valueOf(100);
BigInteger c = a.add(b);
BigInteger d = c.multiply(b.add(BigInteger.valueOf(2)));

操作符

截尾和舍入

float num = 0.7f;
//类型转化对数字进行截尾
System.out.println((int)num); //0
//四舍五入操作
System.out.println(Math.round(num)); //1

注释文档

javadoc 用来提取注释的工具。javadoc 只能为 public 和 protected 成员进行文档注释。

代码规范

可以采用将 public 成员放在开头,后面跟着 protect、包访问权限和 private 成员的创建类的形式,方便类的使用者阅读最为重要的部分(public成员)。

public class OrganizedByAccess {
   
    public void method1() {
   }
    public void method2() {
   }
    protected void method3() {
   }
    void method4() {
   }
    private method5() {
   }
    private int i;
    //...
}

控制执行流程

switch

break 会跳出 switch 语句,没有 break 语句则会一直往下执行。

int i = 1;
switch (i) {
   
    case 0:
        System.out.println("i = 0");
        break;
    case 1:
        System.out.println("i = 1");
        break;
    case 2:
        System.out.println("i = 2");
        break;
    default:
        System.out.println("i >= 3");
}
//输出i = 1

switch (i) {
   
    case 0:
        System.out.println("i = 0");
        //break;
    case 1:
        System.out.println("i = 1");
        //break;
    case 2:
        System.out.println("i = 2");
        //break;
    default:
        System.out.println("i >= 3");
}
//输出
//i = 1
//i = 2
//i >= 3

break 和 continue 实现 goto

public class LabeledFor {
   
  public static void main(String[] args) {
   
    int i = 0;
    outer: // Can't have statements here
    for(; true ;) {
    // infinite loop
      inner: // Can't have statements here
      for(; i < 10; i++) {
   
        print("i = " + i);
        if(i == 2) {
   
          print("continue");
          continue;
        }
        if(i == 3) {
   
          print("break");
          i++;
          break;//break跳出循环,不会执行递增操作
        }
        if(i == 7) {
   
          print("continue outer");
          i++; 
          continue outer;//continue跳到循环顶部,不会执行递增操作
        }
        if(i == 8) {
   
          print("break outer");
          break outer;
        }
        for(int k = 0; k < 5; k++) {
   
          if(k == 3) {
   
            print("continue inner");
            continue inner;
          }
        }
      }
    }
    // Can't break or continue to labels here
  }
}

初始化和清理

成员初始化

局部变量未初始化就使用,会产生编译时错误。类的数据成员是基本类型,它们会有初值(如 int 类型的数据成员初值为0)。

可变参数列表

Java SE5 开始支持可变参数列表。当指定参数时,编译器会将元素列表转换为数组。

public class VarArgs {
   
    public static void printArray(Object... args) {
   
        for(Object obj : args) {
   
            System.out.print(obj + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
   
        printArray(new Integer(1), new Integer(3));
        printArray("tyson", "sophia", "tom");
        printArray(new Integer[]{
   2, 4, 6});
        printArray();//空列表
    }
}

访问权限控制

package 语句必须是文件中第一行非注释代码。

访问权限修饰词

  1. 包访问权限

    默认的访问权限没有任何关键字,通常是指包访问权限,即当前包的所有其他类对当前成员具有访问权限。

  2. protected

    继承访问权限,派生类可以访问基类的 protected 元素。同时,protected 也提供包访问权限,即相同包内的其他类也可以访问 protected 元素。

  3. private

    通过 private 隐藏了代码细节,类库设计者可以更改类内部工作方式,而不会影响客户端。

  4. public

示例代码:

package com.tyson.chapter6_access;
//Cookie.java
public class Cookie {
   
    public Cookie() {
   
        System.out.println("Cookie constructor");
    }
    protected void bite() {
   
        System.out.println("bite");
    }
}

//ChocolateChip.java
public class ChocolateChip extends Cookie {
   
    //私有构造器
    private ChocolateChip() {
   
        System.out.println("chocolate chip constructor");
    }
    //通过静态方法创建类
    public static ChocolateChip createChocolateChip() {
   
        return new ChocolateChip();
    }

    public void chomp() {
   
        //访问父类的protected成员
        bite();
    }
}

class Application {
   
    public static void main(String[] args) {
   
        ChocolateChip chocolateChip = ChocolateChip.createChocolateChip();
        chocolateChip.chomp();
    }
}

复用类

继承语法

派生类如果没有指定某个基类的构造器,则会调用基类的默认构造器,若没有默认的构造器(不带参数的构造器),编译器会报错。

final 关键字

  1. final 数据

    基本类型变量用 final 修饰,则该变量是常量,数值不能改变;对象引用用 final 修饰,则一旦该引用被初始化指向一个对象,就不能再把它改为指向另一个对象,不过对象自身可以修改,只是引用不能修改。

  2. final 参数

    将参数指明为 final,则无法在方法中更改参数。

public class FinalArguments {
   
    void add(final Num num) {
   
        //num = new Num(1); //不能更改final参数
        num.i++;
    }
    void add(final int i) {
   
        //i++; //不能更改final参数的值
    }
}

class Num {
   
    int i;
    public Num(int i) {
   
        this.i = i;
    }
}
  1. final 方法

    final 方法不能被重写,使用 final 方法主要是为了防止继承类修改它的含义。过去使用 final 方法效率会高点,现在的 JVM 相比之前有了很大的优化,没必要通过设置 final 来提高效率。

  2. final 类

    final 类不能被继承。final 类的所有方法都被隐式指定为 final。JDK 的 String 类就是 final 类。

初始化及类的加载

继承与初始化
class Insect {
   
    private int i = printInit("Insect.i initialized");
    protected int j;
    Insect() {
   
        System.out.println("i = " + i + ", j = " + j);
        j = 39;
    }
    private static int x1 =
            printInit("static Insect.x1 initialized");
    static int printInit(String s) {
   
        System.out.println(s);
        return 47;
    }
}

public class Beetle extends Insect {
   
    private int k = printInit("Beetle.k initialized");
    public Beetle() {
   
        System.out.println("k = " + k + ", j = " + j);
    }
    private static int x2 =
            printInit("static Beetle.x2 initialized");
    public static void main(String[] args) {
   
        System.out.println("Beetle constructor");
        Beetle b = new Beetle();
    }
}
/*output
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
Insect.i initialized
i = 47, j = 0
Beetle.k initialized
k = 47, j = 39
 */

多态

封装把接口和实现分离开来,多态消除类型之间的耦合关系。

向上转型:将子类看作是它的基类的过程。子类转型为基类就是在继承图上向上移动。

向上转型

缺陷:“覆盖”私有方法

public class PrivateOverride {
   
    private void f() {
   
        System.out.println("private f()");
    }

    public static void main(String[] args) {
   
        PrivateOverride po = new Derived();
        po.f();
    }
}

class Derived extends PrivateOverride {
   
    public void f() {
   
        System.out.println("public f()");
    }
}
/*
private f()
 */

Derived 类的 f() 实际上是一个全新的方法。基类的 f() 方法在子类 Derived 中不可见,因此不能被重载。

域和静态方法

只有普通的方法调用具备多态性,域和静态方法没有多态性。

构造器和多态

构造器实际上是 static 方法,只不过 static 声明是隐式的,不具备多态性。

构造器的调用顺序
class Meal {
   
    private int weight = get();
    Meal() {
   
        print("Meal()");
    }
    public int get() {
   
        System.out.println("Meal.get()");
        return 1;
    }
}

class Bread {
   
    Bread() {
   
        print("Bread()");
    }
}

class Cheese {
   
    Cheese() {
   
        print("Cheese()");
    }
}

class Lettuce {
   
    Lettuce() {
   
        print("Lettuce()");
    }
}

class Lunch extends Meal {
   
    private int price = food();
    Lunch() {
   
        print("Lunch()");
    }
    public int food() {
   
        System.out.println("Lunch.food()");
        return 1;
    }
}

class PortableLunch extends Lunch {
   
    PortableLunch() {
   
        print("PortableLunch()");
    }
}

public class Sandwich extends PortableLunch {
   
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();

    public Sandwich() {
   
        print("Sandwich()");
    }

    public static void main(String[] args) {
   
        new Sandwich();
    }
} /* Output:
Meal.get()
Meal()
Lunch.food()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
*/

调用顺序:

  1. 按照声明顺序调用基类成员的初始化方法
  2. 基类构造器。从最顶层的基类到最底层的派生类
  3. 按照声明顺序调用成员的初始化方法
  4. 派生类构造器

接口

接口和内部类为我们提供了一种将接口与实现分离的方法。

抽象类

从一个抽象类继承,需要为基类中的所有方法提供方法定义。如果没有提供,则派生类也是抽象类。

如果有一个类,让其包含任何 abstract 方法都没有实际意义,而我们又想阻止产生这个类的任何对象,这时候可以把它设置成一个没有任何抽象方法的抽象类。

接口的域

接口中的域都自动声明为public static final,故接口可以用来创建常量组。Java SE5之前没有提供 enum 实现,可以通过接口实现 enum 的功能。

内部类

内部类允许把一些逻辑相关的类组织在一起,并控制内部类的可视性。内部类可以访问外围类,有些通过编写内部类可以让代码结构更清晰。

.this 和 .new

使用外部类的名字后面紧跟 .this,可以生成对外部类对象的引用。

public class DotThis {
   
    void f() {
   
        System.out.println("DotThis.f()");
    }
    public class Inner {
   
        public DotThis outer() {
   
            return DotThis.this;
        }
    }
    public Inner inner() {
   
        return new Inner();
    }

    public static void main(String[] args) {
   
        DotThis dt = new DotThis();
        DotThis.Inner dti = dt.inner();
        dti.outer().f();
    }
}
//output DotThis.f()

使用 .new 创建内部类的对象。

public class DotNew {
   
    public class Inner {
   }

    public static void main(String[] args) {
   
        DotNew dn = new DotNew();
        DotNew.Inner dni = dn.new Inner();
    }
}

创建内部类的对象,必须通过外部类的对象来创建,在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会隐式连接到创建它的外部类对象上。但是如果创建的是嵌套类(静态内部类),则不需要创建外部类对象。

匿名内部类

//Wrapping.java
public class Wrapping {
   
    private int i;

    public Wrapping(int x) {
   
        i = x;
    }
    public int value() {
   
        return i;
    }
}

//Parcel.java
public class Parcel {
   
    public Wrapping wrapping(int x) {
   
        return new Wrapping(x) {
   //传递构造器参数
            @Override
            public int value() {
   
                return super.value() * 47;
            }
        };
    }

    public static void main(String[] args) {
   
        Parcel p = new Parcel();
        Wrapping w = p.wrapping(8);
        System.out.println(w.value());
    }
}
//output 376

在匿名类定义字段时,还能够对其执行初始化操作。

//Destination.java
public interface Destination {
   
    String readLabel();
}

//Parcel1.java
public class Parcel1 {
   
    public Destination destination(final String dest) {
   
        return new Destination() {
   
            private String label = dest;
            @Override
            public String readLabel() {
   
                return label;
            }
        };
    }

    public static void main(String[] args) {
   
        Parcel1 p1 = new Parcel1();
        Destination d = p1.destination("Puning");
        System.out.println(d.readLabel());
    }
}

匿名内部类没有命名构造器,通过实例初始化给匿名内部类创建构造器的效果。

abstract class Base {
   
    public Base(int i) {
   
        System.out.println("Base constructor, i = " + i);
    }

    public abstract void f();
}

public class AnonymousConstructor {
   
    public static Base getBase(int i) {
   
        return new Base(i) {
   
            //构造器的效果
            {
   
                System.out.println("Inside instance initializer");
            }
            @Override
            public void f() {
   
                System.out.println("In anonymous f()");
            }
        };
    }

    public static void main(String[] args) {
   
        Base base = getBase(47);
        base.f();
    }
} /* Output:
Base constructor, i = 47
Inside instance initializer
In anonymous f()
*/
工厂方法

使用匿名内部类改进工厂方法。

interface Game {
    boolean move();}
interface GameFactory {
    Game getGame();}

public class Games {
   
    public static void playGame(GameFactory gameFactory) {
   
        Game game = gameFactory.getGame();
        while(game.move()) {
   
            ;
        }
    }

    public static void main(String[] args) {
   
        playGame(Checkers.factory);
        playGame(Chess.factory);
    }
}

class Chess implements Game {
   

    private Chess() {
   }
    private int moves = 0;
    private static final int MOVES = 4;

    @Override
    public boolean move() {
   
        System.out.println("chess move " + moves);
        return ++moves != MOVES;
    }

    public static GameFactory factory = new GameFactory() {
   
        @Override
        public Game getGame() {
   
            return new Chess();
        }
    };
}

class Checkers implements Game {
   
    private Checkers() {
   }
    private int moves = 0;
    private static final int MOVES = 3;
    @Override
    public boolean move() {
   
        System.out.println("checkers move" + moves);
        return ++moves != MOVES;
    }

    public static GameFactory factory = new GameFactory() {
   
        @Override
        public Game getGame() {
   
            return new Checkers();
        }
    };
}
/*
checkers move0
checkers move1
checkers move2
chess move 0
chess move 1
chess move 2
chess move 3
 */

嵌套类

将内部类声明为 static,即为嵌套类。普通的内部类隐式保存了一个指向外围类对象的引用,而嵌套类没有。所以创建嵌套类的对象,不需要先创建外围类对象。并且嵌套类不能访问非静态的外围类的成员。

普通的内部类不能包含 static 字段和 static 方法,也不能包含嵌套类,但嵌套类可以包含这些。

public class NestingClass {
   
    public static class StaticInner {
   
        public void dynamicFuc() {
   
            System.out.println("StaticInner动态方法");
        }
        public static void staticFuc() {
   
            System.out.println("StaticInner静态方法");
        }
    }

    public static void main(String[] args) {
   
        StaticInner si = new StaticInner();
        si.dynamicFuc();
        StaticInner.staticFuc();//直接通过类名调用静态方法
    }
}
/*
StaticInner动态方法
StaticInner静态方法
 */

嵌套类没有.this引用。

为什么需要内部类

使用内部类可以实现多重继承。

interface Selector {
   
    boolean end();
    Object current();
    void next();
}

public class Sequence {
   
    private Object[] items;
    private int next = 0;

    public Sequence(int size) {
   
        items = new Object[size];
    }

    public void add(Object x) {
   
        if (next < items.length)
            items[next++] = x;
    }

    private class SequenceSelector implements Selector {
   
        private int i = 0;
        
        public boolean end() {
   
            return i == items.length;
        }
        public Object current() {
   
            return items[i];
        }
        public void next() {
   
            if (i < items.length) i++;
        }
    }

    public Selector selector() {
   
        return new SequenceSelector();
    }

    public static void main(String[] args) {
   
        Sequence sequence = new Sequence(10);
        for (int i = 0; i < 10; i++)
            sequence.add(Integer.toString(i));
        Selector selector = sequence.selector();
        while (!selector.end()) {
   
            System.out.print(selector.current() + " ");
            selector.next();
        }
    }
} /* Output:
0 1 2 3 4 5 6 7 8 9
*/

如果 Sequence.java 不使用内部类,就必须声明 Sequence 是一个 Selector,对于某个特定的 Sequence 只能有一个 Selector。使用内部类的话很容易就可以拥有另一个方法 reverseSelector(),用来生成一个反向遍历序列的 Selector。

局部内部类

interface Counter {
   int next();}

public class LocalInnerClass {
   
    private int count = 0;

    Counter getCounter(final String name) {
   
        // A local inner class:
        class LocalCounter implements Counter {
   
            public LocalCounter() {
   
                // Local inner class can have a constructor
                print("LocalCounter()");
            }

            public int next() {
   
                printnb(name); // Access local final
                return count++;
            }
        }
        return new LocalCounter();
    }

    // The same thing with an anonymous inner class:
    Counter getCounter2(final String name) {
   
        return new Counter() {
   
            // Anonymous inner class cannot have a named
            // constructor, only an instance initializer:
            {
   
                print("Counter()");
            }

            public int next() {
   
                printnb(name); // Access local final
                return count++;
            }
        };
    }

    public static void main(String[] args) {
   
        LocalInnerClass lic = new LocalInnerClass();
        Counter c1 = lic.getCounter("Local inner "),
                c2 = lic.getCounter2("Anonymous inner ");
        print(c1.next());
        print(c2.next());
    }
} /* Output:
LocalCounter()
Counter()
Local inner 0
Anonymous inner 1
*/

局部内部类可以拥有命名的构造器或者重载构造器,而匿名内部类只能使用实例初始化。如果需要不止一个该内部类对象,那么只能使用局部内部类。

内部类标识符

内部类文件的命名格式:外围类名字加上"$",再加上内部类的名字(如果是匿名类,则是一个数字)。

LocalInnerClass$1LocalCounter.class

LocalInnerClass$1.class

容器

容器分类

添加一组元素

public class AddingGroups {
   
    public static void main(String[] args) {
   
        Collection<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
        Integer[] ints = {
   5, 6, 7};
        nums.addAll(Arrays.asList(ints));
        Collections.addAll(nums, 8, 9);
        Collections.addAll(nums, ints);

        List<Integer> list = Arrays.asList(1, 2, 3);
        list.set(1, 90);
        System.out.println(list.getClass());
        //底层是数组java.util.Arrays$ArrayList,不能修改结构,java.lang.UnsupportedOperationException
        //list.add(7);
    }
}

Arrays.asList()返回类型是java.util.Arrays$ArrayList,底层是数组,试图删除或增加元素会抛异常 UnsupportedOperationException。

迭代器

import typeinfo.pets.Pet;
import typeinfo.pets.Pets;
import java.util.Iterator;
import java.util.List;

public class SimpleIteration {
   
    public static void main(String[] args) {
   
        List<Pet> pets = Pets.arrayList(8);
        Iterator<Pet> it = pets.iterator();
        while(it.hasNext()) {
   
            Pet p = it.next();
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
        for(Pet p : pets) {
   
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
        it = pets.iterator();
        for(int i = 0; i < 4; i++) {
   
            it.next();
            it.remove();//删除最近遍历的元素
        }
        System.out.println(pets);
    }
}
/*output
0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
[Pug, Cymric, Pug, Manx]
 */

ListIterator 是一个更为强大的 Iterator 子类型,它只能用于各种 List 类的遍历。ListIterator 可以双向移动。它还可以产生迭代器当前位置前一个和后一个元素的索引,并且可以使用 set() 方法修改最近遍历的元素。通过 listIterator(index) 可以创建指向索引为index的元素的ListIterator。

public class ListIteration {
   
    public static void main(String[] args) {
   
        List<Pet> pets = Pets.arrayList(8);
        ListIterator<Pet> it = pets.listIterator();
        while(it.hasNext()) {
   
            System.out.print(it.next() + ", " + it.nextIndex() +
            ", " + it.previousIndex() + "; ");
        }
        System.out.println();
        while(it.hasPrevious()) {
   
            System.out.print(it.previous().id() + " ");
        }
        System.out.println();
        System.out.println(pets);
        //创建指向索引为index元素处的ListIterator
        it = pets.listIterator(3);
        while(it.hasNext
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值