Java语言程序设计_翁恺

本文最后更新于:2 小时前

初步

基本数据类型

Java语言默认情况下是int类型,如果声明一个长整型变量,需要在后面加一个L

long n = 1000000L;
long n = 1000000;

不加L其实也OK,因为不加L默认该值是一个int,int转为long是安全的,会自动转换。低精度向高精度转换,没有精度损失,所以是安全的;

但是,浮点数不加F默认就是double类型,double精度比float高,高精度向低精度转换,会有精度损失,不会自动转换,所以浮点类型的数后面要加F。

float n = 1.09F;

自字符串连接运算符”+”

“+”两侧必须有一个是字符串

位运算

&& & || |只有布尔值才能进行运算。

&&如果能判断左侧为false时,右侧不再判断;

&左右两侧都要判断。

||如果能判断左侧为true时,右侧不再判断;

|果能判断左侧为true时,右侧不再判断。

下表列出了位运算符的基本运算,假设整数变量 A 的值为 60 和变量 B 的值为 13:

操作符 描述 例子
如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100
| 如果相对应位都是 0,则结果为 0,否则为 1 (A | B)得到61,即 0011 1101
^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001
按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011

初始化

Scanner in = new Scanner(System.in);
//输入此行后回车,会在顶部生成import java.util.Scanner;

输入

int n = in.nextInt() ;//到空格结束 
int n = in.nextLine();//读入一整行

输出

System.out.println( n );//打印后换行

System.out.print( n );//仅打印不换行

数组

创建数组

int [] Array = new int[100];	// 数组初始化为0
int [] Array = { 87, 98, 89, 74, 78 }	// 直接初始化数组

遍历整个数组

for ( int i=0; i<Array.length; i++ ) //Array.length表示数组的长度
{
    /*code*/
}

数组变量:“管理者”

int [] a1 = { 1, 2, 3, 4, 5 };
int [] a2 = a1;
// a1、a2 都是“管理者”,有别于“所有者”
// { 1, 2, 3, 4, 5 } 是数组,是被a1、a2管理的
for ( int i=0; i<a2.length; i++ )
{
    a[2]++;
}
for ( int i=0; i<a1.length; i++)
{
    System.out.println(a1[i]);
}
// 此时 a1[i] = 2
  • 数组变量 是 数组 的 管理者 而非 数组本身
  • 数组 必须创建出来 然后交给 数组变量 来管理
  • 数组变量 之间的 赋值 是 管理权限 的 赋予
  • 数组变量 之间的 比较 是 判断 是否管理 同一个数组

复制数组

​ 遍历,逐一拷贝

int [] a = { 1, 2, 3, 4, 5 };
int [] b = new int[a.length];
for ( int i=0; i<b.length; i++)
{
    b[i] = a[i];
}
for ( int i=0; i<b.length; i++)
{
    System.out.println(b[i]);
}
System.out.println(a==b);	// 仍然输出false

for-each循环

//数据搜索
int [] data = { 3, 2, 5, 7, 4, 9, 11, 34, 12, 28 };
int x = in.nextInt();
int loc = -1;
boolean found = false;
for ( int k : data )	// 对于data数组中每一个元素,循环的每一轮拿出来作为k
{
    if ( k == x )
    {
        found = true;
        break;
    }
}

缺点:只能返回1或0,无存储位置index
for-each循环不能修改数组元素

字符串

创建字符串

String s = new String("Hello,world!");

创建了一个String的对象

用”Hello,world!”初始化这个对象

创建管理这个对象的变量s,让s管理这个对象

String s = "Hello,world!";

编译器帮你创建一个String类的对象交给s来管理

比较两个String

比较内容是否相同

if ( s.equals("something") ) {
    ...
}

String大小的比较

s1.compareTo(s2);

获得String的长度

s.length();

访问String里的字符

s.charAt(index);//index的范围是0到length() - 1

得到字符串

s.substring(n);//得到从n号位置到末尾的全部内容
s.substring(a,b);//得到从a号位置到b号位置之前的内容

寻找字符

从左边开始找

s.index0f(c);//得到c字符所在的位置,-1表示不存在
s.index0f(c,n);//从n号位置开始寻找c字符
s.index0f(t);//找到字符串t所在的位置

从右边开始找

s.lastIndex0f(c);
s.lastIndex0f(c,n);
s.lastIndex0f(t);

其他String操作

s.startsWith(t);
s.endsWith(t);
s.trim();
s.replace(c1, c2);
s.toLowerCase();
s.toUpperCase();

不可变的String

所有的字符串都是不可变的,对它们的操作的结果都是制造新的字符串出来

Math类

abs(-12);//绝对值
pow(3, 2);//3的2次幂
random();//生成一个伪随机数
round(10.645);//四舍五入

进阶

构造函数

  • 如果有一个成员函数的名字和类的名字完全相同,则在创建这个类的每一个对象的时候会自动调用这个函

  • 这个函数不能有返回类型

函数重载

  • 一个类可以有多个构造函数,只要它们的参数表不同
  • 创建对象的时候给出不同的参数值,就会自动调用不同的构造函数
  • 通过this()还可以调用其他构造函数:只能在构造函数里面出现,只能是第一句,只能使用一次
  • 一个类里的同名但参数表不同的函数构成了重载关系

package //TODO

static

static变量:类变量,不属于任何一个对象,属于这个类

static成员变量只有在类的装载的时候被初始化,在后面不会被初始化,只初始化一次

类函数 //TODO

容器类

  • ArrarList<String> notes = new ArrayList<String>; //自动在顶部生成 import java.util.ArrayList;

    容器类型<元素类型>

    ArrayList of String叫做泛型类,称为容器

  • 容器类有两个类型:容器的类型 和 元素的类型

ArrayList的操作

private ArrayList<String> notes = new ArrayList<String>();//容器类,用于存放对象
notes.add(s);
notes.size();
notes.add(location, s);
notes.remove(index);
notes.toArray(a);

对象数组

对象数组于基础类型的数组不同

String[] a = new String[10];

做了十个格子,每个格子里面都是String类的管理者,但是这个时候没有管理任何值,所以每个格子都是null

//赋值操作
for ( int i = 0; i < String.length; i++ ) {
    a[i] = "" + i;
}

对象数组中的每个元素都是对象的管理者,而非对象本身

toString

任何一个Java类,只要实现

public String toString() {
}

就能让

System.out.println();

直接替你输出这个对象,它会主动地调用toString函数,用这个函数产生的String进行输出。

HashMap

体现在代码当中,硬编码越少越好

HashSet

HashSet为数学上的集合,在集合中没有重复元素

HashSet<String> s = new HashSet<String>();
s.add("first");
s.add("second");
s.add("first");
for ( String k : s ) {
	System.out.println(k);
}//遍历后输出为second first ,只有最后的一个first
//System.out.println(s);
//也可以用上面这一行的方式直接输出s,输出的结果里面带有方括号,表示这是一个容器

HashMap

哈希表是一种数据结构,在这种数据结构里面,所有的东西是以一对值放进去的,一个叫做key,一个叫做value。key的所有类型必去都是对象,而不能是基本元素,比如Integer(int的包裹类型),String

private final HashMap<Integer, String> coinnames = new HashMap<Integer, String>();

public Coin() {
    coinnames.put(1, "penny");
    coinnames.put(10, "dime");
    coinnames.put(25, "quarter");
    coinnames.put(50, "half-dollar");
    coinnames.put(50, "五毛");
    System.out.println(coinnames.keySet().size());//所有的key有多少个
    System.out.println(coinnames);
}

public String getName(int amount) {
    return coinnames.get(amount);
}

遍历哈希表

for ( Integer k : coinnames.keySet() ) {//遍历哈希表
        //coninnames.keyset()给出了这个哈希表所有的key的集合
        String s = coinnames.get(k);
        System.out.println(s);//输出
    }

key是唯一的,同一个key放进去了多次,留下来的,只有最后一次

继承

避免出现代码重复的情况,提高代码的可维护性

子类和子类型

CD extends Item

  • 类定义了类型
  • 子类定义了子类型
  • 子类的对象可以被当作父类的对象来使用
  • 子类对象可以赋值给父类的变量
  • 子类对象可以传递给需要父类对象的函数
  • 子类对象可以放进存放父类对象的容器里

子类型于赋值

子类对象可以赋值给父类的变量

一个父类Vehicle,两个子类Car,Bicycle

Vehicle v1 = new Vehicle();
Vehicle v2 = new Car();
Vehicle v3 = new Bicycle();

多态变量

  • Java的对象变量是多态的,他们能保存不止一种类型的对象
  • 它们可以保存的是声明类型的对象,或声明类型的子类的对象
  • 当把子类的对象赋给父类的变量的时候,就发生了向上造型

造型cast

把一个类型的变量赋给另一个类型的变量,这个过程叫做造型

  • 子类的对象可以赋值给父类的变量(注意!Java中不存在对象对对象的赋值)

  • 父类的对象不能赋值给子类的变量

    Vechicle v;
    Car c = new Car();
    v = c;	//可以
    c = v;	//编译错误
  • 可以用造型

    c = (Car)v;	//	只有当v这个变量实际管理的是Car才行

造型

  • 用括号围起来放在变量的前面
  • 对象本身并没有发生任何变化,所以不是类型转换,而是把cd当作Item来看
  • 运行时有机制来检查这样的转换是否合理: ClassCastException

向上造型

  • 拿一个子类的对象,当作父类的对象来使用
  • 向上造型是默认的,不需要运算符
  • 向上造型总是安全的

函数调用的绑定

  • 当通过对象变量调用函数的时候,调用哪个函数这件事情叫做绑定
    • 静态绑定:根据变量的声明类型来决定
    • 动态绑定:根据变量的动态类型来决定(Java默认都是动态绑定)
  • 在成员函数中调用其他成员函数也是通过this这个对象变量来调用的

覆盖override

  • 子类和父类中存在名称和参数表完全相同的函数,这一对函数构成覆盖关系
  • 通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所管理的对象所属的类的函数

类型系统

Object类

Object类的函数

  • toString(); //返回一个对象的字符串的表达形式
  • equals(); //比较两个对象的内容是否相同

代码规范

增加可扩展性

  • 可以运行的代码!=良好的代码
  • 对代码做维护的时候最能看出代码的质量
  • 如果想要增加一个方向,如down或up

用封装来降低耦合

  • Room类和Game类都有大量的代码和出口相关
  • 尤其是Game类中大量使用了Room类的成员变量
  • 类和类之间的关系称作耦合
  • 耦合越低越好,保持距离是形成良好代码的关键

用接口来实现聚合

  • 给Room类实现的新方法,把方向的细节彻底隐藏在Room类内部了
  • 今后方向如何实现就和外部无关了

用容器来实现灵活性

  • Room的方向是用成员变量表示的,增加或减少方向
    就要改变代码
  • 如果用Hash表来表示方向,那么方向就不是“硬编码”
    的了

以框架+数据来提高可扩展性

  • 命令的解析是否可以脱离if-else
  • 定义一个Handler来处理命令
  • 用Hash表来保存命令和Handler之间的关系

抽象函数/抽象类

  • 抽象函数—表达概念而无法实现具体代码的函数

  • 抽象类——表达概念而无法构造出实体的类

  • 带有abstract修饰符的函数

  • 有抽象函数的类一定是抽象类

  • 抽象类不能制造对象

  • 但是可以定义变量

    • 任何继承了抽象类的非抽象类的对象可以赋给这个变量

实现抽象函数

  • 继承自抽象类的子类必须覆盖父类中的抽象函数
  • 否则自己成为抽象类

两种抽象

  • 与具体相对
    • 表示一种概念而非实体
  • 与细节相对
    • 表示在一定程度上忽略细节而着眼大局

拿到陌生程序

1.找main,读懂每一句

2.展开看类

1.找到最小的类,追溯到最顶上的父类

数据与表现分离

  • 程序的业务逻辑与表现无关

    • 表现可以是图形的也可以是文本的

    • 表现可以是当地的也可以是远程的

(细胞自动机)

View和Field的关系

  • 表现与数据的关系
  • View只管根据Field画出图形
  • Field只管数据的存放
  • 一旦数据更新以后,通知View重新画出整个画面
    • 不去精心设计哪个局部需要更新
    • 这样简化了程序逻辑
    • 是在计算机运算速度提高的基础上实现的

责任驱动的设计

  • 将程序要实现的功能分配到合适的类/对象中去是设计中非常重要的一环

网格化

  • 图形界面本身有更高的解析度
  • 但是将画面网格化以后,数据就更容易处理了

接口

  • 接口是纯抽象类
    • 所有的成员函数都是抽象函数
    • 所有的成员变量都是public static final //属于整个类,不会被改变
  • 接口规定了长什么样,但是不管里面有什么

实现接口

  • 类用extends,接口用implements
  • 类可以实现很多接口
  • 接口可以继承接口,但不能继承类
  • 接口不能实现接口

面向接口的编程方式

  • 设计程序事先定义接口,再实现类
  • 任何需要再函数见传入传出的一定事接口而不是具体的类
  • 是Java成功的关键之一,因为适合多人同时写一个大程序
  • 也是Java被批评的要点之一,因为代码量膨胀起来很快

练习项目

进阶里面的知识点全部结合下列项目食用

clock

package display;

public class Display {
    //只有成员变量是私有才能保护该变量不会被外界随意使用
    private int value = 0;  //private关键字只能用于成员变量以及成员函数
    private int limit = 0;  //private变量只能在本类中使用

    public Display(int limit) {  //构造函数
        this.limit = limit;
    }

    public void increase() {
        value++;
        if( value == limit ) {
            value = 0;
        }
    }

    public int getValue() {
        return value;
    }

    public static void main(String[] args) {
    }
}
package clock;

import display.Display;

public class Clock {
    private Display hour = new Display(24);
    private Display minute = new Display(60);

    public void start() {
        while (true) {
            minute.increase();
            if ( minute.getValue() == 0 ) {
                hour.increase();
            }
            System.out.printf("%02d:%02d\n", hour.getValue(), minute.getValue());
        }
    }

    public static void main(String[] args) {
        Clock clock = new Clock();
        clock.start();
    }
}

notebook

package notebook;

import java.util.ArrayList;

public class Notebook {
    private ArrayList<String> notes = new ArrayList<String>();//容器类,用于存放对象

    public void add(String s) {
        notes.add(s);
    }

    public void add(String s, int location) {
        notes.add(location, s);
    }

    public int getSize() {
        return notes.size();
    }

    public String getNode(int index) {
        return notes.get(index);

    }

    public void removeNote(int index) {
        notes.remove(index);
    }

    public String[] list() {
        String[] a = new String[notes.size()];
//        for ( int i = 0; i  < notes.size(); i++ ) {
//            a[i] = notes.get(i);
//        }
        notes.toArray(a);
        return a;
    }

    public static void main(String[] args) {
//        int[] ia = new int[10];
//        String[] a = new String[10];
//        System.out.println(ia[0]);
//        System.out.println(a[0]);
        Notebook nb = new Notebook();
        nb.add("first");
        nb.add("second");
        nb.add("third",1);
        System.out.println(nb.getSize());
        System.out.println(nb.getNode(0));
        System.out.println(nb.getNode(1));
        nb.removeNote(1);
        String[] a = nb.list();
        for ( String s : a ) {
            System.out.println(s);
        }

    }

}

coins

package coins;

import java.util.HashMap;
import java.util.Scanner;

public class Coin {

    private final HashMap<Integer, String> coinnames = new HashMap<Integer, String>();

    public Coin() {
        coinnames.put(1, "penny");
        coinnames.put(10, "dime");
        coinnames.put(25, "quarter");
        coinnames.put(50, "half-dollar");
        coinnames.put(50, "五毛");
        System.out.println(coinnames.keySet().size());//所有的key有多少个
        System.out.println(coinnames);

        for ( Integer k : coinnames.keySet() ) {//遍历哈希表
            //coninnames.keyset()给出了这个哈希表所有的key的集合
            String s = coinnames.get(k);
            System.out.println(s);//输出
        }
    }

    public String getName(int amount) {
        if ( coinnames.containsKey(amount) )//如果存在amount的一个key
            return coinnames.get(amount);
        else
            return "NOT FOUND";
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int amount = in.nextInt();
        Coin coin = new Coin();
        String name = coin.getName(amount);
        System.out.println(name);
    }

}

demo

Java库

数组排序

Arrays.sort(数组名);

保留小数

https://blog.csdn.net/lls60s/article/details/92849357

字符转int

Integer.parseInt(String s ,int radix)

比如:parseInt(1010,2)
意思就是:输出2进制数1010在十进制下的数.

进制转换

10进制转化其他进制 对应的方法,参数:n(原10进制数据),r(进制), 返回值
10进制转2进制 Integer.toBinaryString(n); 一个二进制字符串.
10进制转8进制 Integer.toOctalString(n); 一个八进制字符串
10进制转16进制 Integer.toHexString(n); 一个16进制字符串
10进制转 r 进制 Integer.toString(100, 16); 一个r进制字符串


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!