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 协议 ,转载请注明出处!