Introduction-简介

Machine language 机器语言
Assembly language 汇编语言
Hight-level language 高级编程

机器语言:计算机是一个二进制的系统,意味着在计算机的世界中,只有0和1这两个数字存在。计算机是理解并且通过执行机器语言来进行工作的,一段机器语言包括两个部分 op code操作码 和 operands操作计算的数字

这样子的话对人类非常不友好,还有点反人类,所以科学家发明了汇编语言Assembly language

这样子的话可以将机器语言转换为我们能够理解的汇编语言,就非常易于编写和理解
但是,如果要用C语言实现一个问题,从1加到100,要实现这样的一个程序,应该如何完成?

在编程语言中,我们有编程规范programming paradigm

在这门课中,我们的主要注意力集中在Object-oriented programming面向对象的程序设计,比如Java

Java编程语言的图标是一个咖啡的图像

但是最开始的时候,Java并不是这个名字,她最开始的名字叫做Oak,直到1995年才被改名为Java

Java有3种最基本的类别
分别为:Java SE (Standard Edition) Java ME(Micro Edition) Java EE(Enterprise Edition)
在未来的时候我们可能会用到 EE服务器 或者 ME移动端,但是这学期我们主要学习SE,也就是客户端版本。
接下来我们需要了解一些关键词

API (application program interface)库,表示别的程序员已经编好的我们可以直接使用的库,也有一种叫法 library,JDK (Java Development Toolkit) 开发工具包,如果我们想让电脑运行JDK程序的话,需要在电脑上安装了JDK才能去运行Java程序
IDE(Integrated development environment) 开发环境 ,简单的来说就是用来高亮语法之类的,能够让我们码字的时候更加舒爽

一段简单的输出文字的小程序

Public class Welcome {
Public static void main(String[] args){
//display message Welcome to Java! On the console
System.out.printIn(“Welcome to Java!”);
}
}

我们的源文件在经过特定的编译后,会生成一个由Java虚拟机可以运行支持的二进制文件,我们所编译的源文件一般会以.java为特定结尾的文件,文件经过编译后悔生成.class结尾的文件。在例子中,所使用的是特别简单的输出功能。
我们这门课会使用Y. Danicl Liang 的 Java Programming
The best way to learn is by practice

那么,我们这学期又要学习什么?
这本书一共有40多个章节,但是我们只关注前面的基本编程部分。所以计划是覆盖1-13章。
好消息是,这本书还有中文翻译版,可以对照着学习

Chapter 2: Elementary Programming

变量 variable

首先,先举个栗子,如果我们需要计算一个圆的面积,那我们需要使用πr^2,也就是朗朗上口的"πR方"
先科普一个小东西,圆的半径之所以被称为r 是因为其英文为radius半径
那么把它放在程序里的话,首先要有一个思路

  1. 输入圆的半径
  2. 使用郎朗上口的公式计算
  3. 输出酷炫的结果

开始工作!
首先我们先确定一个变量variable ,变量的值是随时可以改变的
这里需要养成一个习惯,最好使用表述性的名字,能够从这个名称了解到这个变量的作用是什么。尽量不要使用xyz之类的
然而在Java中,变量其实是有很多的数据类型
当我们想要创造一个数据常量的时候,需要去声明我需要创造的这个数据的类型是什么
类型大概可以分为以下几种:
数据类型

这六种数据类型用来表示数字,这里值得注意的是
看到Bytes, Short, int, long,这四个数据类型,是用来表示整数类型的,无论是正数还是负数都ok
他们之间唯一的区别就是所能支持的最大值
举个栗子,如果我们需要128这个数字,那我们就不能使用bytes作为这个数据的数据类型,要用short或int
决定他们的是在电脑里的字节
在上学期讲过字节和存储大小的关系,这里就不再多BB了

我们将视线转移到float 和 double 上
这两个都可以表示浮点数,可以为小数。不像上面的那几个只能是整数
float 和double 所能表示的数据大小也不同
double能表示的数据大小是float的两倍

在C语言中,我们学习过int, float之类的,在Java,也有不同的变量,Java有8中基本的变量类型,我们将其称作Primitive data type原始的变量类型

double yuandebanjin;
double yuandemianji;

比如这个变量名称就皮的不行
在Java中有两种不同的注释,这里的和C语言中的一毛一样,这里就不多加叙述了

写代码的习惯

关于写代码的习惯,请看这两种习惯:

system.out.println(3+4*4);
system.out.println(3 + 4 * 4);

显然后面这种让人更易于阅读和理解

还有前段缩进
然后还有了个奇妙的名字
Next-line style

public class Welcome 
{

public static void main(String[] args) 
{
    // TODO Auto-generated method stub
    System.out.println("SHOW ME YOUR ID");
}

}
End-of-line style

public class Welcome {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    System.out.println("SHOW ME YOUR ID");
}

}

输入和输出

接下来讲讲Java的输入和输出

System.out表示输出
System.in表示输入
Scanner表示让用户输入

比如我们想让用户输入一个值得时候,就需要使用

Scanner input = new Scanner(System.in);

来声明我们需要在程序中使用到scanner这个功能,然后在程序中就可以直接输入

double radius = input.nexDouble();

来让用户输入数值了
像上面的那个nextdoor♂(雾) nextDouble();
当我们的变量名称是double的时候使用才有效果
如果变量名称是其他的比如bytes 之类的呢?
那就按部就班地跟着一起改嘛
更改变量名称

Identifiers 标记符

还有值得注意的是,Java语法中有一个很重要的术语,Identifiers 标识符 ,例如 类,变量,方法,常量
Java是对大小写敏感的,area和Area和AREA是完全不一样的3个字符
Java的标识符必须以下划线或者$起头,亦可以以英文字母起头

我们写程序去生成变量的时候,当你生成一个变量,在内存中就会被分出一部分空间来给这个变量
比如说:

int i , j , k;
int count = 1;
int i = 1 , j = 2;

每一个变量都有一个作用域 scope ,之后会有更加详细的讲解

assignment赋值

assignment赋值
赋值一般使用这个

variable = expression;

左边写变量右边写赋值
不要忘记最后的小分号

还有一件事,Java里还有一个玩意叫Constants,叫做常量,我们可以在赋值的时候给一个常量赋值,这也就表示这个常量以后都不会改变
赋值语法:

final datatype CONSTANT-NAME = value

Naming Conversions 命名规则

Java语法中比较重要的命名规则
当你在命名一个变量或者方法的时候,变量的名字是由小写字母组成的
但是假设变量名称中包含几个不同的英文单词,一个长单词中的第一个单词的首字母小写,第二个单词的首字母要大写,比如computerArea,这里包含Computer 和Area 两个单词。
这样的命名方法叫做驼峰命名法camel case
我们在命名Java中的类的时候,每个首字母都要大写

当要命名一个常量的时候,常量的名称都要大写
比如MAX_VALUE

运算法则

Java也有自己的运算法则
就像RT说的那样,电脑十分聪明,但是有一点点蠢萌
Addition 加法
Subtraction 减法
Multiplication 乘法
Division 除法
Remainder 余数
这几个东西的关系,可以理解为下面那样

关系

在这里我们可以实际运用一下这个运算法则
比如一个小程序,让用户输入时间(秒)之后可以自动转换

import java.util.Scanner;

public class DIsplayTime {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("Enter an interger for seconds:");
        int seconds = input.nextInt();
        int minutes = seconds / 60;
        int remainingSeconds = seconds % 60;
            System.out.println(seconds + "seconds is" + minutes +" minutes "+ remainingSeconds + " seconds ");
    }
}

在这里需要读懂这个小程序,我们来一行一行地看


import java.util.Scanner;

这里是加入Scanner这个功能,这个功能的作用就是加入让用户输入这个功能,前面只有加入了这个功能在程序里才能正常使用


public class DisplayTime {

这一行在我们每次创建新项目的时候都会自动帮我们写好,意思是指代组


public static void main(String[] args) {

这句话在最开始创建的时候,如果勾选了这个框框的话,Eclipse就会帮我们创建好
创建的时候的菜单
这句话里面的main代表程序的起始点,可以称之为启动子,是一个起点,当我们点击了运行项目的代码的时候,程序就会从这个位置开始运行程序,然后从这个位置一行一行地执行下去。


System.out.println("Enter an interger for seconds:");

在屏幕上输出一句话:输入一个数字


int seconds = input.nextInt();

这一行声明了一个int类型的变量,然后通过调用input.nextInt()的这样一个方法,让用户输入了一个整数并且将这个数值付给"seconds"


int minutes = seconds / 60;

这里是将用户输入的变量除以60,得到的结果就是分钟,并且将得到的结果赋给"minutes"


int remainingSeconds = seconds % 60;

这里是将用户输入的变量除以60所得到的余数,比如70除以60的余数就是10,并且将这个值赋给"remainingSeconds"


System.out.println(seconds + "seconds is " + minutes + "minutes " + remainingSeconds + "seconds");

这里是在屏幕上显示出来用户输入的是多少分钟和多少秒


Exponent Operations 指数运算

同时Java里也是存在指数运算的
在Java中有个库叫Math,这个库中有许许多多关于数学运算的代码
这里取得是一个Power指数来做一个栗子
比如我们需要2的3次方
那我们可以输入

System.out.println(Match.pow(2,3));

这条代码表示输出2的3次方,结果为8
同时次方也可以是0.5次方,也就是根号

Numeric Literals 数值直接量

这一部分是一个概念,就是Java中在进行数值表达的时候在进行的一个“数值直接量”的概念
我们java中敲入的数字,比如int a = 100;默认为十进制的100,计算机不会将其认为二进制的
但是某些情况下我们需要表示二进制的数字的时候,我们需要在这些数字前面加上一些特殊的符号
比如在二进制数字前面加上0B,计算机就会强制将其认为是二进制的数字,比如0B1111,计算机就会识别为十进制的15而不是1111
如果要表达八进制的数字,前面需要加上 0 ,就是数字“零”,比如07777表示4095
如果想表达一个十六进制数字,就需要在前面加上一个 0X ,比如0XFFFF表示的就是65535

我们的浮点数据也有一个数值的直接表达量
比如double = 2.5,这个2.5就是浮点数字的直接表达量,但是这个数字会被当成一个double类型的数字,而不是float类型的数字
虽然double都是浮点数,但是所表示的范围不同,所以是不一样的数据类型
当我们使用float = 2.5 时,程序会报错。修复这个BUG的方法就是使用 float r = 2.5F 这样就行了,在数字后面加上一个F就完事儿

顺带一说,Double能表示小数点后的16位,而float只能表示小数点后的8位

老师的实际演示提到了一个很好玩的问题
在Eclipse中,输入long = 2147483648;后显示报错,但是讲道理Long这个数据类型可以存储很大很大的数字,肯定不止这么一点点,那又是为啥呢
因为我们所输入的2147483648这个数字,Java并不认为是Long的数据类型,之前提到过所有直接输入的数字Java都会默认为Int的数据类型,然而int最多只能存储最大值为2147483647的数据,所以我们这里需要在数字后面加上一个大写或者小写的L,这样就没报错了

Augmented Assignment Operators 简捷运算符

所谓的便捷运算,就是省略了一些需要敲入的文字,简单来说可以这样表示:
+=

同样在Java中也有i++ 和i--(回想起了当时被RT支配的恐惧)
i++

在这里肯定有人要问了,++放在前面和放在后面有什么区别呢?
这里就设计到一个专业的表格了
i++和++i
这个东西以前RT讲过
就是先加和后加的问题
如果放在等式里求结果的话还是很头疼的一件事情
他两的区别不过是先加后执行其他的指令和先执行其他运算后加,这里一般会放在循环里用,i会用一个值来限定需要加和减多少次

Numeric Type Conversions 数值类型转换

这里再讲一个Java的赋值类型的互换
Java可以把两个范围不同的浮点数相互赋值
用代码表示的话就是酱:

float n5;
double n6;
n5 = 5.0F;
n6 = 5.0;

n6 = n5;

那如果我们稍微改一下代码,将其改为这样

float n5;
int n6;
n5 = 5.0F;
n6 = 5.0;

n6 = n5;

这样子是不会有报错的,因为Java会自动把整数的数值转换为浮点数
但是当我们把最后一行改为 n5 = n6 ,也就是说把浮点数转换为整数,这就会报错
如果我们非得进行这种数据转化呢?
我们就需要进行 explicit casting 显示 数据转换
这玩意就是加了个括号,将其改为这样
n5 = (byte)n6;
这样就不会报错了,这种操作叫做强制的数据类型转换

接下来讲讲print 和 println的区别
首先先来讲讲多出来的那个ln
这个表示Line,也就是下一行
那估计不用讲都懂了,有ln的表示输入完括号内的内容之后换到下一行,新的内容后在下一行显示

PPT里给到一个问题,以下代码的输出结果是?

System.out.println(1/2);

结果是0
没想到吧哈哈哈哈哈
嗯没错我也没想到
因为这两个都是int的数据类型
我们需要规定其为小数才行
解决办法可以按照上面那个“显示 数据转换”的方法来更改
可以将其改为

System.out.println((double)1/2);

这样子就没问题了

Chapter 3 : Selections

在上一章的学习中,我们学习了很多表示数字的数据类型,比如int, double之类的
在这一章中,我们将学习一个新的数据类型,叫做布尔变量

Boolean data type 布尔变量

之前在学习C语言的时候应该也是用过的
至少逻辑方面都差不多
布尔变量只有两个值,分别是True 真False 假
一般这种布尔变量的值是可以通过关系型运算Relational Operators来获得的
所谓关系型运算,就是我们数学中的大于等于小于之类的,简单可以归纳为下图所示的东西
关系型运算

注意图后的True和False值

在Java中,判断是否相等时使用 == ,判断不相等时使用 !=
接下来我们用代码来看看什么叫做布尔变量

if (radius < 0){
    System.out.println("Incorrect input");
    }
else{
    area = radius * radius * 3.14159;
    System.out.println("Area is " + area);
}

简单的来说就是如果True的话就运行第一个括号内的内容,False的话就运行或号外的内容
在这里的每一个括号和结束用的分号都非常关键,不能省略
不过值得一提的是,当if条件句里的语句只有一条的时候,if后面的花括号是可以省略的

import java.unit.Scanner;

public class SimpleIfDemo {
  public static void main(String[] args){
  Scanner input = new Scanner(System.in);
  System.out.println ("Enter an interage : ");
  int number = intput.nextInt();

  if (number % 5 == 0){
    System.out.println("HiFive.");
  }
  if (number % 2 == 0){
    System.out.println("HiEven");
    }
  }
}

Nested if and Multi-Way 嵌套式选择结构

简单来说就是if里面再套一个if,我们可以在if或者else的结构中继续写

构成双if结构

 if(baabalabala){
   if(balabalabala){
        ....
   }
}

那么如果我们需要写出一个程序,来记录和表示不同的学生的分数
比如100到90分是A,90到80分是B,以此类推
这里可以使用else if 语句来完成

if (score >= 90.0)
  System.out.println("A");
else if (score >= 80);
  System.out.println("B");
else if (score >= 70);
  System.out.println("C");
else if (score >= 60);
  System.out.println("D");
else 
  System.out.printfln("F");

Generating Random Numbers 普通的随机数字

举个栗子,如果我们需要取一个随机的数字,但是又不想让自己来取,那可以交给电脑来去
说实在的这一点还是满实用的

import java.util.Scanner;

public class SubtractionQuiz{
  public static void main(String[] args){
    //1.Generate two random single-digit intergers
    //获取随机数字
    int number1 = (int)(Math.random() * 10);
    int number2 = (int)(Math.rancom() * 10);
    //看到后面的那个 * 10 了没?
    //那个是用来限定范围的,这样范围就被限定为0.0 ~ 9.9(注意不包含10)
    //看到前面的那个int了没,虽然java随机生成的数字会包含小数,但是前面的int限定了我们只要整数部分

    //2.If number1 < number2,swap number1 with number2
    //因为我们想要用大的数字来减去小的数字,所以我们在后面的数字大于前面的数字时,交换两个数字
    //毕竟小的数字在前面的话就会出现负数了
    if (number1 < number2){
      int temp = number1;
      number1 = number2;
      number2 = temp;
      }
    //3.Prom the student to answer "What is number1 - number2"
    System.out.println("What is " + number1 + " - " + number2 + "?");
    Scanner input = new Scanner(System.in);
    int answer = input.nextInt();

    //4.Grade the answer , display the result
    //这里要检验用户是否是小学生智商
    if (number1 - number2 == answer)
      System.out.println("No xiaoxuesheng!");
    else
      System.out.println("xiaoxuesheng!\n" + number1 + "-" + number2 + "should be " + (number1 - number2) );
    }
}

Logical Operators 逻辑运算符

记得之前去图书馆找RT玩的时候,他给我讲过这玩意
这里就不多BB啦,想起当时RT中午请我喝咖啡就很开心
逻辑运算符
哦对了,这里 ^ 叫做异或,用来检查两个数字是否相同,如果相同的话就是假,不同的话就是真。就是一个是真的,一个是假的,如果套在这个符号的话,那就是真的。但是如果两个都是真的或者两个都是假的,套在这个符号里他们就都是假的。

举个栗子,我们先规定两个数字,age = 24 , weight = 300

!(age > 18)//F
!(weight == 310)//T
(age > 28) && (weight <= 300)//F
//实际在Java运行的时候,计算机会从左到右去执行
//首先左边得到的表达式是F,但是右边的是T
//但是Java在执行&&这个符号的时候是不会去看符号右边的数值的
//这里要留意一下
//当然其他符号Java都会去看符号两边,就这个符号比较奇葩
(age > 34) II (weight >= 310)//F
//这里两个II表示上面逻辑运算符的or
//因为网站不允许上传这玩意所以还是挺绝望的
//我可能是个假的站长
//辣鸡宝塔
(age > 34) ^ (weight > 300)//F
(age > 34) ^ (weight >= 300)//F

接下来我们来实操一下

import java.unit.Scanner;

public class TestBooleanOperators {
  public static void main(String[] args){
  //create a Scanner
  Scanner input = new Scanner(System.in);

  //Receive an input
  if (number % 2 == 0 && number % 3 == 0)
    System.out.println(number + " is divisible by 2 , 3");

  if (number % 2 == 0 II number % 3 == 0)
  //这里两个II同样代指上表中的or
    System.out.println(number + "is divisible by 2 or 3");

  if (number % 2 == 0 ^ number % 3 == 0)
    System.out.println(number + "is divisible by 2 or 3, but not both.";
  }
}

Switch Statements Switch语法

inport java.unil.Scanner;

public class TeatBooleanOperators {
  public static void main(String[] args) {
    //create a Scanner
    Scanner input = new Scanner(System.in);

    //Receive an input 
    System.out.println("Enter an interger: ");
    int number = input.nextInt();

    if (number % 2 == 0 && number % 3 == 0)
      System.out.println(number + " is divisible by 2 and 3.");

    if (number % 3 == 0 II number % 3 == 0)
      System.out.println(number + "is divisible by 2 or 3/");

    if (number % 2 == 0 ^ number % 3 == 0)
      System.out.println(number + " i divisible by 2 or 3 , but not both");

    }
  }

Switch的语法和C语言的非常相似
估计自己也能看的懂
那就拿老师在上课的时候举的例子吧

import java.util.Scanner;

public class ChineseZodiac {
  public static void main(String[] args) {
    Scanner input = new Scanner(SYstem.in);
    System.out.println("Enter a year: ");
    int year = input.nextInt();

    switch (year % 12){
      case 0 : System.out.println("Monkey");break;
      case 1 : System.out.println("Rooster");break;
      case 2 : System.out.println("Dog");break;
      case 3 : System.out.println("Pig");break;
      case 4 : System.out.println("Rat");break;
      case 5 : System.out.println("Ox");break;
      case 6 : System.out.println("Tiger");break;
      case 7 : System.out.println("Rabbit");break;
      case 8 : System.out.println("Dragon");break;
      case 9 : System.out.println("Snake");break;
      case 10 : System.out.println("Horse");break;
      case 11 : System.out.println("Sheep");
      //最后一行这一个Break加不加效果都一样
    }
  }
}

在这里注意到有一个Break语句
Break这个关键字还是蛮重要的
这句话的意思就是跳出当前,在这里是跳出当前Switch

Conditional Expression 条件表达式

条件表达式栗子
看上面这张图,如果想实现左边的这个语句的话,可以用右边这一行就可以搞定出来,这种东西叫做条件表达式
这个就是如果我们想给给变量赋值的,如果X大于0的话,就给y赋1,如果X不大于0的话,就给y赋-1
这种情况下我们可以不使用if - else,用一句话把它给搞出来
就像上图所示中的那样
右边的条件表达式可以有个公式套一下
max = (num1 > num2) ? num1 : num2;
这个问号简直通俗易懂,最后的num1 表示前面括号内结果为T,num2表示结果为F

Operator Precedence and Associativity 运算优先级和结合性

这玩意就好像我们小学先做乘除再做加减的情况
这些不同的运算也有一个先后的顺序
可以总结为一个表格

运算优先级
看箭头,最上面的是最高级的,越往下越来越低级

Chapter 4: Mathematical Functions, Characters, and Strings

Common Mathematical Functions

之前的提到过Math.random()的玩意,就是获取一个随机的数字
关于角度的计算
常用的数学运算的方法

sqrt(x)这个表示的是平方根,在后面有一个比较重要的编程练习会用到,所以现在可以先记一下

Math.max(2 , 3) return 3
//这里就是选取括号内的最大的数字
Math.max(2.5 , 3) return 3.0
//简单的来说就是数字会变为相同的格式
Math.min(2.5 , 4.6) returns 2.5
就算是min也是一样的道理
Math.abs(-2) return 2
这里的abs指代的是绝对值
Math.abs(-2.1) return 2.1
接下来我们来看看下面这两行代码

(int)(Math.random() * 10)
//返回的值会在0~9之间
50 + (int)(Math.ranndom() * 50)
//返回的值会在50 ~ 99之间
Ramdom 这玩意会随机的选取0.0到1.0之间的任意一个数字,就是0.4啊0.5啊之类的。
后面乘以10就是将选取出来的数字乘以10,那得到的数字就不再是小数了,而是整数
当然还可以在前面弄个加号,再乘以50之类的骚操作
这里我们可以总结出一个公式:

a + Math.rancom() * b
//返回的数字应该是 a 到 a+b 之间的数字之一,包括 a+b

Charachter Data Type and Operations

我们在之前讲过7种原始的数据类型,这里的char是第八种数据类型

那么前7中数据类型分别是什么呢?

boolean 布尔变量、byte 数字、char 字符、short 数字、int 数字、float 数字、double 数字、long 数字

先来看看我们给字符变量时使用的方法

char a = 'A';
char b = '5';

这玩意和我们之前学过的赋值int类型的数据也是差不多的方法,不过值得一提的是,这里需要用单引号来把赋值的值框起来

记得在上学期,CC讲过计算机是二进制的世界,所有的字符都会被转换为二进制的编码
所以我们也可以返璞归真,用二进制编码的值来代表它

char letter = '\u0041'

//字母A对应的Unicode编码是0041
这样子输出的值依然是A

Excape Sequences For Special CHaracters 特殊字符的转义序列

Java占用了一些特殊的符号来指代一些特殊的意思
比如我们写注释的时候用到的是双斜杠

转义字符

举个栗子,在某些特殊的时候我们要使用一些特殊的符号
比如我们想要输出 He said " Java is fun"
那么我们需要键入 System.out.println("He said "Java is fun"");
但是这时候Java就不开心了,两个冒号是什么鬼啊,完全理解不能

就好像当时RT说的那句话一样,She is smart but a little bit stubit
这时候我们就需要加上一个完美的右斜杠来表示我们需要输出这个双引号
将代码改为 System.out.println("He said \"Java is fun\"");
这样子就没问题了

The String Type

在Java语法中,字符串String是属于一个类,这玩意在之后才会讲,现在只要知道如何使用就好了
首先来看看语法

String message = "Wellcome to Java";

这里的message我们可以用自定义的字符去替代,就是用于储存字符串的
值得注意的是,赋值的时候,需要用双引号框起来

同样的,和C语言相似的,我们对特定的字符串也有许多方法,最常用的有
字符串的使用方法

在这里有一个非常重要的语句,是 charAt(index)();
他会返回一个特定的值,这个值由index的数组下标的位置来决定

数组下标

首先,字符串会存放在特定的数组里,并且数组的下标是从0开始计算的
看到上面那张图了嘛
当我们键入

System.out.println(c.charAt(11));

输出应该是 J
差不多就像往木箱子里摆酒瓶似的,需要哪个就拿哪个

Readding a String from the Console

同样的,Java能够读取用户输入的内容,这里有两种语法

String s1 = input.next()
String si = input.nextLine()

他两的区别就是读取单个单词(通过空格来区分)和读取完整的一行的东西

但是,如果我们想获得一个特定的字符呢?
也别问为什么,就是想获得呢?
这个就要结合之前的charAt语法了,因为Java中没有获得单个字符的语句
看看下面这串代码

Scanner input = new Scanner(System,in);
System.out.println("Enter a chatacter");
String s = input.nextLine();
char ch = s.charAt(0);
System.out.println("The character entered is " + ch);

只有通过这两个方法结合起来我们才能获得一个特定的字符

在Java中,我们还可以对已经取得的字符进行一系列的操作
字符操作指南

那么有没有一个程序能总结这一整章的知识点呢?那肯定有
举个栗子,我们需要一个能够将16进制的字符转换为10进制的字符的小程序

Chapter 5: Loops

看到这个循环了没
想到了当年被RT支配的恐惧

While loop

其实循环这个概念在之前学C语言的时候我们就曾经讲过
Java中也是类似的
至少理念什么的都差不多

首先我们先来看看while loop

while (loop-continuation-condition)
{
    //loop body
    Statement(s);
}

还是用一张图来表示比较好

while循环

int count = 0;
while (count < 100)
{
    System.out.println("Welcome come to Java!");
    count++;
}

int count = 0;
while (count <= 100)
{
    System.out.println("Welcome come to Java!");
    count++;
}

先来看看这两行代码
那么问题来了,这两个代码中,分别会循环多少次呢?
第一个会循环100次,第二个会循环101次

当我们在设置循环的时候,需要检查我们的循环是不是无限循环
就像当时在C语言中用无限循环做了个1G的文件
结果删掉的时候还花了我1分钟.....
无限循环在这里就不多BB啦
反正也就是逻辑问题

其实有时候我们也需要用一些无限的循环,比如需要运行一个程序多次但不退出的时候
就像之前提到过的,给小学生的算数题目
如果第一次输入错了就退出程序然后还要重新开程序的话,这未免也太反人类了
这时候我们就需要用一个while循环来让用户可以一直一直的输入

while ( number1 - number2 != answer)
    {
    System.out.println("You answer is wrong. Try again.");
    //当答案不正确的时候,让用户再次输入一次
    answer = input.nextln();
    //用户可以再次输入结果,这时候回到while循环并检查是否满足条件
    }
System.out.println("You are correct!");

接下来我们来看一个概念 sentinel value 标记值

代码2

在上面的代码中有这样一行

whild (data != 0)
这一行代码在以后估计也会经常用到
很多时候我们在写while循环的时候,条件中使用的是一些特殊的变量,这个变量很多时候是有特殊性的
这里的data的值是否为0,就是标记值 sentinel value
也就是说只要data不为0的时候就结束循环

Do-while loop

首先先来看看语法

do{
    loop body;
    Statement(s);
}while(loop-continuation-condition);

do-while

简单的来说,while是先检查再执行,do- while是先执行再检查
哦对了,顺带一提,do-while循环需要使用一个分号,放在whlie的后面

For loop

老样子,先来看代码

for (initial-action; loop-cotiunation-condition;action-ater-eac-interation)
{
    //loop body
    Statement(s);
}

for loop

for循环和C语言的差不多,括号内需要有两个分号,来分割开来3个指令
第一个指令用来表示在循环开始之前要去做的事情
第二个指令表示循环的判断条件
第三个指令表示在循环结束的时候需要去执行的代码
其实和C语言的差不多

Nested loops嵌套循环

这次我们从一个看起来很酷炫的东西来看看语法
这段小程序能输出一个9乘9乘法口诀表

for(int i = 1 ; i <= 9 , i ++)
{
    System.out.println(i + " | ");
    for (int j = 1 ; j <= 9 ; j++)
    {
        //Display the product and align properly
        System.out.printf("%4d" , i * j);
        //首先我们来看看这个%4d
        //%d表示会输出十进制的数字,中间的那个4表示每个数字都要占多少个位置,这里4意味着4个空格的位置
        //正4表示把数字靠右对齐
        //如果是负4的话表示将数字靠左对齐
    }
System.out.println();
}

这里说到一个printf,这玩意也是表示格式化输出
这里列出一些常用的格式化输出

格常用的式化输出

public class TestPrintf { 
public static void main(String[] args) { 
//定义一些变量,用来格式化输出。 
    double double_number = 345.678; 
    String text = "你好!"; 
    int int_number = 1234; 

    //"%"表示进行格式化输出,"%"之后的内容为格式的定义。 
    System.out.printf("%f",double_number); //"f"表示格式化输出浮点数。 
    System.out.println(); 

    System.out.printf("%9.2f",double_number); //"9.2"中的9表示输出的长度,2表示小数点后的位数。 
    System.out.println(); 

    System.out.printf("%+9.2f",double_number); //"+"表示输出的数带正负号。 
    System.out.println(); 

    System.out.printf("%-9.4f",double_number); //"-"表示输出的数左对齐(默认为右对齐)。 
    System.out.println(); 

    System.out.printf("%+-9.3f",double_number); //"+-"表示输出的数带正负号且左对齐。 
    System.out.println(); 

    System.out.printf("%d",int_number); //"d"表示输出十进制整数。 
    System.out.println(); 

    System.out.printf("%o",int_number); //"o"表示输出八进制整数。 
    System.out.println(); 

    System.out.printf("%x",int_number); //"x"表示输出十六进制整数。 
    System.out.println(); 

    System.out.printf("%#x",int_number); //"#x"表示输出带有十六进制标志的整数。 
    System.out.println(); 

    System.out.printf("%s",text); //"s"表示输出字符串。 
    System.out.println(); 

    System.out.printf("输出一个浮点数:%f,一个整数:%d,一个字符串:%s",
    double_number,int_number,text); 
    //可以输出多个变量,注意顺序。 
    System.out.println();  
    } 
}

ok那我们回到正题
输出的结果应该为
乘法口诀

其实我觉得把它理解为套娃也可以
RT最爱干的事情就是循环中的循环中的循环
像极了恋爱循环
se no~
然后喊人回答
那可是我见过的最安静的教室了

循环中的Break和continue

感觉全世界的Break都一样
只要有个Break就会跳出当前循环
无论是否满足当前循环条件
因为和以前的实在太相似所以这里就不多BB了

但是continue呢?
这个可值得讲讲

continue

continue其实是用来跳过某一次循环的部分代码
就是跳过当前正在循环的这次代码,然后又返回到循环最开始的时候
当然continue结束后的代码都不会被运行了

Chapter 6: Methods 方法

记得在C语言中,RT也讲过这种东西
C语言里的叫做Function,Java里叫Mathods,感觉都差不多

Eclipse 的章节整理


老师在这里提到了一个关于Eclipse 的整理小技巧
我们可以把不同的章节都给命名好然后丢到对应的package里面
这样美观大方还便于查找
比如就像这样
代码整理技巧

Parameters 方法的参数

首先,假如我们需要一个小程序,就是计算1加到10的结果
当然不是由我们去计算,是电脑通过一个循环去计算
这里可以使用一个for 循环去计算

public static void main(String[] args)
{
    int sum = 0;
    for (int i = 1 ; i <= 10 ; i++)
    {
        sum += i;
    }
    System.out.println("The sun of 1 to 10 is " + sum);
}

那如果我们再加一些,需要1加到100的结果呢?
其实也就加个0
简单明了

public static void main(String[] args)
{
    int sum = 0;
    for (int i = 1 ; i <= 100 ; i++)
    {
        sum += i;
    }
    System.out.println("The sun of 1 to 10 is " + sum);
}

那如果我们需要35加到66的结果呢?

public static void main(String[] args)
{
    int sum = 0;
    for (int i = 35 ; i <= 66 ; i++)
    {
        sum += i;
    }
    System.out.println("The sun of 1 to 10 is " + sum);
}

其实这里准确的说我们是在复习上节课的内容
For循环的运算
在老师的程序中,如果我们需要在同一个程序中运算这些代码的话,记得在每次运算之前把sum的值归零
sum = 0;

但是像这种功能非常类似的代码,是一个相似性很高,并且重复度也很高的代码
每次我们在复制黏贴这些代码的时候,我们都需要去检查一下单个变量的值是否有改变
虽然说这里只是几行的代码,但是如果说是那种超大型的项目,一行一行地去看的话估计会看到心态爆炸
对于秃子来讲这个过程是完全没必要的,我们应该避免这种复制黏贴代码的方法
无论是C语言还是Java,都有一种使得代码能够被重复利用的方法
这个方法就是 Method

我们可以把上面的这个代码改成这样

public static int sum(int i1, int i2)
//这里是sum方法
//sum我们可以自定义为其他字母
//皮一点可以命名为heji
//哦对了记得遵循命名规则,就是都是由小写字母开头的
{
    int result = 0;
    for (int i = i1; i <= i2; i++)
    {
        result += i;
    }
    return result;
}

public static void main(String[] args)
//这里才是Main
{
    System.out.println("The sun of 1 to 10 is " + sum(1, 10));
    //这里sum(1, 10);的意思是使用上面的那个sum的功能
    System.out.println("The sun of 20 to 37 is " + sum(20, 37));
    System.out.println("The sun of 35 to 49 is " + sum(35, 49));
}

Defining a Method

我们在写代码的时候,很多时候都要使用一些自定义的方法 Defining a Method
就好像我们之前用的那个生成随机数字的方法
这个其实是一个现有的方法,它们存在于Java的库中,我们只是在调用它们
但是我们的编程中很多时候是需要我们去自定义方法的

我们可以把一个方法定义为两种类型
如果一个方法有返回值,那我们可以称其为 value-returning method
如果没有返回值的话,可以叫 void method,空方法

当我们自定义方法的时候,最基本需要包含4个部分,这4个缺一不可
Method name 方法名称
Parameters 参数
Retuen Value type 返回值类型
body 主体部分

在自定义方法的第一行,我们称之为方法头 Method header
然后在method header里包含4样东西
modifiers 修饰符
return value type 返回值类型
method name 方法名称
parameters 参数

第一行的大概解释

用图来说的话

自定义方法

return value type 返回值类型
method name 方法名称
formal parameters 参数形式
parameter list 参数列表
method signature 方法结束的标志
method body 方法主体
这里面的public 和 static 我们在之后会慢慢讲,现在不重要啦
现在只要知道写这两个玩意就行

public static int max(int num1, int num2)

//这里的int的话是最重要的,叫做返回值

Invoke (calling) method 调用方法

当我们自定义方法了之后,下一步就是调用方法

调用方法

简单的来说就像上图中的那样
我们在使用一个方法的时候,如果说这个方法存在返回值,那我们在调用这个方法的时候可以被视为获得了一个值
调用完方法之后返回的这个值会被赋值到其他东西上
但是如果所调用的一个方法没有返回值,那么调用的这个方法会被视为一个被执行的语句,程度相当于输出一行东西

其实准确的说,当一个代码被调用的时候,系统会生成一个表格,这张表格里写了要被记录下来的信息,这个记录存放了与之相关的参数和变量的值,这张记录表会被存放在内存中,这样的一个操作,我们有一个很砖业的术语去称呼它,叫 stack,具体的就是指调用方法的时候产生的这么一个东西。而这个Stack在计算机里是个非常重要的概念,叫 。栈是一种数据结构,遵循先进后出的原则

当一个方法去调用另外一个方法的时候,调用的那个叫做Caller's(调用者),一般都是主方法去调用其他方法,那主方法就是caller's 。 当主方法发出调用其他方法的指令后,主方法已经运行的代码会被暂时存放起来,然后会生成一张船新的表格来执行即将要被调用的玩意

当方法调用完成之后,并且返回值返回到主方法之后,电脑会抹去其在内存中的位置,说白了就是一次性的用完就丢那种

用于存放记录表中的栈采用了一种策略叫 last-in , first-out,叫做后进先出,我们可以来结合一张表来看看

后进先出

Return Value 返回值

如果有返回值的话,要记得定义一下返回值类型
返回值的类型要和我们定义的是一致的才行
如果实在懒得管就直接全部double
double保平安

这里用cc的代码来展示一下一下返回值类型

public class TestMax{
    public static void main (String[] args){
        int i = 5; 
        int j = 2;
        int k = max (i , j);
        //这里是调用方法max
        System.out.println("The maximum of " + i + " and" + j + " is" + k);
    }
  
    //上面所调用的方法写在了这里
    public static int max(int num1, int num2){
        int result;
        if (num1 > num2)
            result = num1;
        else
            result = num2;
        retuen result;
        //一般方法都会有一个返回值,返回值的类型我们在设定方法的时候就已经定义好了
    }
}

用一张图来表示的话

返回值

void Method Example

谁说方法一定要有返回值
也可以稍微改变一下思路嘛
老师po出了一段代码

public class TestVoidMethod {
    public static void main(String[] args) {
        System.out.println("The grade is ");
        printGrade(78.5);

        System.out.println("The grade is ");
    }

    public static void publicGrade(double score) {
        if (score >= 90.0) {
            System.out.println('A');
            //('A')  突然发现这是个表情
            //这里之所以能用单引号是因为单引号表示单个字符
            //如果是多个字符的话就必须要用双引号了
        }
        else if (score >= 80) {
            System.out.println('B');
        }
        else if (score >= 70) {
            System.out.println('C');
        }
        else if (score >= 60) {
            System.out.println('D');
        }
        else {
            System.out.println('F');
        }
    }
}

这里的第二个方法没有返回值,表示其为一个void方法
同样的,表达同一个意思的代码可以修改为

public class TestReturnGradeMethod.java
    public static void main(String[] args) {
        System.out.println("The grade is " + getGrade(78.5));
        System.out.println("The grade is " + getGrade(59.5));
    }

    public static char getGrade(double score) {
        if (score >= 90)
            return 'A';
        if (score >= 80)
            return 'B';
        if (score >= 70)
            return 'C';
        if (score >= 60)
            return 'D';
        else
            return 'F';
    }
}

简单的来说,同样的一个意思可以用返回字符的方法,也可以用不返回字符的方法

Pass arguments by value

parameter order association 参数顺序匹配
你看上面那个小程序,里面有一个getGrade(78.5)
这个小括号里面放着的叫做参数列表
当我们调用方法的时候,小括号里的内容要和我们定义的参数列表相匹配才行
按照顺序来匹配才行,也就是一样的顺序才行
举个栗子

public static void nPrintln(String message , int n) {
    for (int i = 0 ; i < n ; i ++)
        System.out.println(message);
}

这个小程序的功能就是设定输入的信息和设定输出多少行
当我们call这个方法的时候,括号内的内容也要和上面nPrintln()里的内容顺序和类型相匹配才行
不然就没办法正常运行了

哦对了,当我们用方法的时候,相同的变量的值会跨方法传递
但是变量本身的值并不会因为传递之后就发生改变
这玩意叫做pass-by-value通过值传递
具体是个啥玩意咧
通过一个例子来看看吧

public class Increment {
    public static void main (String[] atgs) {
        int x = 1;
        System.out.println("Before the call, x is " + x);
        increment(X);
        System.out.println("After the call, x is " + x);
    }
  
    public static void increment(int n) {
        n++;
        System.out.println("n inside the method is " + n);
    }
}

这里不妨先思考一下程序输出的结果是什么
下面这里是答案

程序输出结果

Before the call, x is 1
n inside the method is 2
After the call, x is 1

public class Increment {
    public static void main (String[] atgs) {
        int x = 1;
        System.out.println("Before the call, x is " + x);
        //这里x = 1
        increment(X);
        //这里call方法increment
        //当方法call完之后,会输出 n = 2
        System.out.println("After the call, x is " + x);
        //这里的就是重点了,这里还是会输出x = 1
        //虽然call了方法,但是其并没有改变x的值
    }
  
    public static void increment(int n) {
        n++;
        System.out.println("n inside the method is " + n);
    }
}

我们在调用方法的时候参数是以值得形式被传递过去的,意味着这里传递的并不是x本身,传递的是x代表的值
在方法内部只不过是对传递过来的x进行操作罢了
但是方法内部并没有对x做任何的修改
所以x的值任然是1

整型浮点布尔char
八种类型记下
编程的数据都靠它
乘除减加
基础运算啊
单等号赋值运算
别记差
循环和多选择
逻辑多
条件变量一定要记得
如果说
忘赋值了
死循环内存溢出等你呢
一学JAVA我就
公开保护默认和私有
静态实例抽象类接口
多态继承真要学很久
谓我何求

其实我感觉还是CC唱的好听

Method Oveloading 方法重载

当我们定义多个方法的时候,其实是可以用相同名字的
不过有个小条件,就是用相同名字的话,他们的signatures签名(这里指返回值类型和参数列表)不一样才行
这也就意味着在我们代码中可以定义两个一模一样的名字的代码
当然多个main是不行的
因为main永远只有一个
举个栗子

 public static int max(int num1 , int num2)
 public static double max(int num1, int num2)

这两个就是可以存在于同一个程序里的两个不一样的方法
那么有没有再详细一点的栗子呢?

public class MethodOverload {
    public static void main(String[] args) {
        System.out.println("The bigger number is " + max(1 , 2));
        //使用第一个方法
        System.out.println("The bigger number is " + max(1.5 , 2.8));
        //使用第二个方法
        System.out.println("The bigger number is " + max(1 , 2 , 3));
        //使用第三个方法
    }

    public static int max(int n1, int n2) {
        System.out.println("1");
        //just a mark
        if(n1 > n2)
            return n1;
        else
            return n2;
    }
    public static double max(double n1, double n2) {
        System.out.println("2");
        //just a mark
        if (n1 > n2)
            return n1;
        else
            return n2;
    }
    public static int max(int n1, int n2, int n3) {
        System.out.println("3");
        //just a mark
        return max (max(n1 , n2), n3);
        //先对比前两个数字的大小然后返回最大的数字
        //之后将返回回来的数字与第三个数字比较,得到最大的数字
}

那么有个小例题,假如给出了两个方法的定义:

public static double m(double x, double y);
public static double m(int x, double y);

那么以下三个选项分别调用了什么方法?

a. double z = m(4 , 5);
b. double z = m(4 , 4.5);
c. double z = m(4.5, 5.4);

答案

我们定义的方法中只有两个m的方法
当我们调用方法m的时候,它就会去挨个儿判断上面两个方法哪一个是最合适的
如果找到一个最合适的,它就会去执行
如果找完所有的都没找到的话,它就会报错

先看a选项,虽然都是int类型,但是我们之前提到过,4可以被看作4.0,简单的来说就是可以理解为一个小数
但是由于在寻找方法的时候会挨个儿找最合适的那个,所以当检查第一个数字的时候,电脑就会找到第二个选项,就是int和double组合的那个
因为5可以被所做5.0,所以会被匹配到第二个方法里

再来看b选项,完美符合第二个方法,所以就会直接丢到第二个方法里

最后来看c选项,完美符合第一个方法,所以就会直接丢到第一个方法里

那么加量不加价,如果还有选项D: double z = m(4.5 , 4);呢?
反正我一看就知道肯定是第一个了
因为电脑是挨个儿检查的
所以4.5没办法通过int这一关
第二个马上就被pass掉了
果断丢到第一个方法里

那我们稍微换一下题目

public static double m(**int** x, **int** y);
public static double m(int x, double y);

那么以下三个选项分别调用了什么方法?

a. double z = m(4 , 5);
b. double z = m(4 , 4.5);
c. double z = m(4.5, 5.4);
可见只是把double换成了int,结果就大大不同了
a和b选项这里就不多bb,咱们直接看c选项
因为电脑没办法找到符合c选项的方法,所以程序会直接报错

The scope of variables 变量的作用域(范围)

记得在C语言的时候,曾经去问过RT一个问题,然后他给我讲了locoal variable菊部变量
一个菊部变量的作用域就是从他的定义开始到它所在的这个块的结尾,必须先被声明定义才可以被使用,这是个基本的规律和原则

那么什么叫做“这个块”的结尾呢(更加专业的说法叫做作用域)

scope of i and j

说白了就是一个loop
就是从i这个语句开始到它所在的这个大括号的结尾都是它的作用域
记得是从这句话开始的(就是它的声明位置)

哦对了,如果我们在for循环小括号里已经声明了i的值为int了,那我们之后在循环体内部还可以使用 int i = 100嘛
答案是不行的,在相同的作用域内重复声明了相同名字的数据类型的变量,是会报错滴
如果用代码说明的话就是这样

public static void method1(){
    for(int i = 1; i < 100; i++) {
        //如果我在这里加上int i = 100就会报错
        int j;
    }
}

那么如果我们再搅屎棍一点,把j加到外面呢?
用代码来表示为:

public static void method1(){
    for(int i = 1; i < 100; i++) {
        int j;
    }

//如果我们在这里加上j = 100是会报错的
//因为j的作用域在上一个大括号就已经结束了
}

两个独立的i

看到上面这张图片,两个i是相互独立的,所以当我们再次使用的时候就要再一次的定义

错误的演示

上面这张图片可以看到第二个int是会报错的
在同一个作用域我们只需要声明一次就可以了

Method Abstraction方法的抽象

这里提到了一个理论上的概念,叫做方法的抽象
同样的我们可以把它叫做信息的隐藏 information hiding 和信息的封装 encapsulation
抽象是一个非常重要的概念,得靠我们自己慢慢理解
比如这个问题
我们用了很多次的System.out.println这行代码,这里面的代码是怎么写的呢?
这到底是如何去实现的
实际上我们是一点都不了解的
对于我们来讲这可能就像一座冰山
我们只需要知道冰山上是怎么样的就行了
不过我们也不需要知道,我们需要只需要知道如何使用就行了

Chapter 7: Arrays 数组

记得在C语言里面,也有提到过数组这个概念
记得RT也说过这玩意会很难结果花了3节课来讲这玩意
还好期末考试没考....

Array Basic

首先老样子先来看看语法

int a[] = new int[5];
//套公式的话就像这样elementType[] arrayRefVar;
//举个栗子 double [] myList;

数组能被视作一个变量或者是一个数据集合
不过值得一提的是,当一个数组被创建出来之后,其大小就是固定的不会被改变的了
其实数组就像冰块盒,单行的那种,我们能往盒子里放东西,同样也能取东西出来
哦对了记得数组是从 0 开始的啊

public static void main(String[] atgs)
{
    int[] array1;
    double[] array2;
    char[] array3;
}

我们可以声明一个数组(也就是上面的那个array1)为一个变量,相似于int a;

既然我们已经声明了一个数组,但是并没有真正的创建出来
为了创建一个数组,剩下的需要做的事情就是给它赋值了

 array1 = new int[10];
 array 2 = new char[100];

上面的那个就是声明变量并且创建变量,但是这个过程其实可以在一行代码中就解决掉

int [] array4 = new int[5];

不过我觉得能用两行还是用两行比较好
比较到后面检查来说的话也比较方便嘛
一行就像浓缩咖啡,容易呛着

关于我们用数组和它的储值的话可以用一张图来表示出来

数组

之后,想再次查看数组的长度的话,可以使用

数组名字.length
来查看数组的长度

关于数组的其他操作


当我们输入数组后加个句号(英文的句号)的时候,就会弹出这样一个菜单
数组的操作
这个菜单列出的都是关于数组的基本操作
可以选择一些需要的

记得之前CC讲过一个message.length, 感觉这两个玩意的性质应该都差不多是一个意思
就是用来计算长度的嘛

那么问题来了,如果说我们需要输出一个数组里面的数字,咋整?
讲道理用一个循环就好了
数组输出的套路一般都是array[i],其中的i要求就是i++,说白了就是加一加一加一这样来输出
用代码表示的话可以表示为

for ( int i = 0; i < 5 ; i++)
{
    System.out.println("array[i]");
}

这样子就没问题了
当我们前面对array数组进行了一系列的赋值操作之后,这里就能一行一行地显示出来数组里的数字

Accessing Array Elements 引用数组元素

这里提到的一点就是
当我们去引用我们创建的数组里某一个具体位置的元素的时候,这个数组下标是从 0 开始的
然后最大的数字是一直到 (数组大小 - 1) 的这个位置

比如说我们创建了一个大小为10的数组,那这个数组的下标的最大值就是 9 而不是 10

Foreach Loops 关于Foreach 循环

这里补充一个小知识点
可以把它叫做数组的便利
就是可以用比较简洁的方法来将数组里的元素快速地提取出来
首先先来看语法

for (double e: myList)
{
    System.out.println(e);
}

就是在for循环中加上 double e: array 就可以了
里面的x可以换成任意的变量,只要不冲突的就行
这句话的意思就是将数组里的数字取出来存放在变量X中,这里我们可以在循环内部加上一个println语句来将其输出出来

哦对了,我们定义的这个用来存放数据的这个数据类型,一定要和数组里面的数据类型是一致的
比如数组里的是分数的话,那我们定义数组类型的时候就不能定义为int
还是以前那句话,double保平安

数组的综合运用

这节课老师用边上课边讲的方式,喊我们做了个综合的小练习
这里就po出我的答案啦

package ClassWork;
public class ArrayExerise {
public static void main(String[] args) {
    // TODO Auto-generated method stub
    int[] Jackey;
    Jackey = new int[5];
    //or you can write like that:
    //int[] Jackry = new int[5]
    //or int Jackry[] = new int[5]
    //both ok

    //Initializing arrys with random values 使用随机数字初始化数组
    for (int i = 0; i < Jackey.length ; i++)
    {
        Jackey[i] = (int)(Math.random() * 100);
        //[0,1) 
        //0.555555 -- 5.5555555 -- 55
        //() will change the level
        //加了括号的内容会改变运算的优先级
    }

    //Display arrays 显示数组内容
    for (int i = 0; i < Jackey.length ; i++)
    {
        System.out.print(Jackey[i] + " ");
    }
    System.out.println();

    //Sum all elements
    int sum = 0;
    for (int i = 0; i < Jackey.length; i++)
    {
        sum += Jackey[i];
    }
    System.out.println("sum :" + sum);

    //Find the largest element
    int large = Jackey[0];
    for (int i = 1; i < Jackey.length ; i++)
    {
        if(Jackey[i] > large)
        {
            large = Jackey[i];
        }
        //这里就算去掉上面这个if的花括号也是ok的
    }
    //上面这个for的花括号也可以省略
    //因为里面的if是一条语句
    //在Java的语法中,只有分号会被视为一条语句
    System.out.println("largest : " + large);

    //Random shuffling 随机洗牌
    for (int i = Jackey.length - 1; i > 0 ; i--)
    {
        //generate a random index j
        //[0 , i]
        int j = (int)(Math.random() * (i + 1));
        int temp = Jackey[i];
        Jackey[i] = Jackey[j];
        Jackey[j] = temp;
    }
    for (int a = 0; a < Jackey.length ; a++)
    {
        System.out.print(Jackey[a] + " ");
    }
    //Display arrys
    System.out.println();

    //shift elements 移位
    int temp = Jackey[0];
    for (int i = 1; i < Jackey.length ; i++)
    {
        Jackey[i - 1]= Jackey [i];
    }
    Jackey[Jackey.length - 1] = temp;

    //Display arrays
    //foreach loop
    for (int output: Jackey)
    {
        System.out.print(output + " ");
    }
}
}

Copying Arrays 数组的复制

如果说人类史上最伟大的发明是什么
那我会回答是Ctrl + c and Ctrl + v
当然这种方法也能用在数组上

首先我们先看回到我们以前的赋值方法
在我们赋值数字的时候,一般都是用a = b 来将b的值赋值给a
不过你放心,在数组里的方法肯定不一样,因为剧本不允许

首先我们要先清楚数组的概念
数组可以将其理解为一个小仓库和名字,假如我们有两个小仓库,名字分别为list1 和 list2

数组概念1

list1 和 list2 都分别有对应的仓库与其连接,互不干扰

但是当我们执行list2 = list1 这个语句之后,其就会变为

数组概念2

可以看到原本属于list1的仓库被贴上了list2的标签,这也就意味着list1 和 list2都指向同一个仓库了
结果空巢仓库list2就没人管了
这显然不是我们想要的结果

那么什么是正确操作呢?
为了给数组进行正确的赋值操作,使得两个数组的值完全一模一样,我们可以用3种方法

  1. 使用循环赋值
  2. arraycopy 方法
  3. clone方法

首先我们先来看一个一个赋值的基本方法
比如先把数组导入到一个循环里面,然后使用循环将数组里面的数字一个一个的提取出来,并赋值到它应该去的地方
先用一段代码来表示这个

int[] sourceArray = {2, 3, 4, 5, 10};
int[] targetArray = new int [scourceArray.length];
for (int i = 0; i < sourceArray.length; i++)
{
    targetArray[i] = sourceArray[i];
}

这里就不解释代码了,这段代码比较简单易懂
我们把重点放在第二种方法上----arraycopy method 数组复制

所谓的arraycopy方法其实就是调用一个存在于系统里的方法,来给指定的数组进行复制

arraycopy(sourceArray, srcPos, targetArray, tarPos, length);

括号内的东西:原数组的名字,原数组的位置,目标数组的名字,目标数组的位置,赋值对少个
所谓原数组的位置的意思就是你想从几号元素开始复制
最后的赋值多少个的意思就是 按照2345这样的顺序依次复制下去
比如我们最开始希望把源数组的2号位置赋值给目标数组的一号位置,如果我们最后那个数字填的是10,那第一个数字赋值完成后,就会开始把源数组3号位置的值赋值给目标数组的2号位置,并且以此类推

现在有一个问题,已经声明大小的数组,我们能用相同的语句去改变它的大小嘛
用代码来表示的话就是

int[] myList;
myList = new int[10];
mylist = new int[20];

答案是不行的
因为这样的代码并没有改变数组的大小
原来那个大小为10的数组任然在内存中驻留
而我们的myList指向了另外一个大小为20的数组
因为在内存里面,数组是随着创建的完成就会被分配出一个空间来储存它的
当我们输入myList = new int[20]的时候,内存就会自动分配一个20空间的地方来存放这个新数组
但是原来那个数组就没人管了
又成了个空巢数组

Passing Array to Methods 把数组在不同方法中传递

我们可以先自定义一个方法

public static void printArray(int[] array)
{
    for (int i = 0; i < array.length; i++)
    {
        System.out.println(array[i] + " ");
    }
}

然后我们可以在主方法中call它,记得在括号内放上需要的数据

printArray(new int [] {3, 1, 2, 6, 4, 2})

这样子就没问题了
至于使用什么方法传递出去的话,可以在call方法前先定义int数组,到时候传递的话就是直接把整个数组个发过去了

哦对了,这个和我们之前那个pass by value 有一个很重要的区别
当我们调用一个方法的时候改变的是变量的值而不是变量本身
但是我们把Array传递到其他方法的时候,我们可以在传递的时候会加上具体的数字,比如

printArray(new int[] {1, 2, 3, 4, 5});

或者也可以直接使用

printArray (a);

来将数组直接显示出来
(看起来之前那个有些麻烦)
这样子就能将数组传递到别的方法里,然后数组在方法内部进行了修改,意味着数组本身就被修改了

我们把数组传递给方法的时候,可以被描述为 pass by-sharing 即通过分享的方式进行传递,意味着array所指代的东西被分享给了调用的方法。哦对了,方法内部的数组和被传递过去的被调用的数组是同一个数组
这个和数值在方法之间的传递有着根本的区别
所以我们在方法内部改变其内容的时候,数组的内容是真的被改变了的
当我们回到主方法再调用其的时候,其内容是真的被改变了的

Heap 堆

我们之前讲过一个Stack 栈 的概念
这玩意是后进先出,就像往桶子里放东西一样
如果要拿出来的话都是先拿最上面的,也就是后进来的

但是Heap 堆 这玩意就有点点不同了
这个像个管子,先进来的就会先出去
heap

Return an Array from a Method 把数组作为一个返回值

我们不止可以用一个返回值将结果从一个方法输出出来,也可以试试看数组
举个栗子

public static int[] reserse (int[] list)
//我们需要在方法头定义我们需要返回一个数组
{
    int[] result = new int[list.length];
    for (int i = 0, j = result.length - 1; i , list.length; i++, j--)
    {
        result[j] = list[i];
    }
    return result;
    //这里返回一个数组
}

哦对了你知道什么是return 0 嘛
记得在C语言里面,call一个方法是必须要Return的,如果没啥可返回的话,那就Ruturn 0
但是在Java中,如果没啥可返回的话,那就在方法头那里定义为void就可以了
但是在需要返回东西的方法里面,方法头定义void的话是一定会报错的
举个栗子,比如我们需要返回一个一维数组
那我们方法头就应该写 int[]

Searching Arrays 数组的搜寻

搜寻和排序是计算机里的非常重要的内容,在未来我们会学习一门砖门的课程来详细讲解
这里我们需要有一个基本的了解

我记得上学期CC在一开学就讲过这个东西,还是熟悉的PPT还是熟悉的内容

就是在一堆名字中找到一个指定的名字
首先将名字按照首字母排序完成,然后按照二分搜索 Binary Search 来搜索

The Linear Search Approach 线性查找法

说白了就是按顺序 sequentially 的
依次比较数组中的元素
我们只需要用一个循环去查找就行了就是把数组里的元素一个一个和我们的关键字进行对比
然后返回结果
就算没匹配到也要返回结果
举个栗子

public class LinearSearch
    public static int linearSearch(int[] list, int key)
    {
        for (int i = 0; i < list.length; i++)
        {
            if (key == list[i])
            {
                return i;
            }
            return -1;
        }
    }

如果能找到的话,就返回指定数字位于数组中的第几位
然后如果找不到的话,就返回一个指定的数字,当然这个数字我们可以自定义的

然后我们在Main里面只需要call一下这个方法就可以了
比如

int i = linearSearch(list, 4);

其返回值应为 1,意识是找到了,在数组的第二位
哦对了,这里再强调一下,数组是从0开始计算的!

The Binary Search Approach 二分查找法

如果我们想使用二分查找法的话,这个方法会更快一点
所谓的二分法就是
先将现有数据排序 must already be ordered ,然后将数据的中间值和关键字做对比
如果在数据中间值之前,那就搜索中间值往上的内容,往下的内容就不考虑了
在中间值往上的内容中,取中点在进行一次运算和取值
这样子就有点像2的多少次方的感觉
因为都是一半一半地来做
这样子能够大大提高搜索的效率
这个方法叫做二分查找法

二分查找法

package binarySearch;
import java.util.Scanner;
public class TestBinarySearch {

    public static void main(String[] args) {
        int[] list = {2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79};
        Scanner input = new Scanner(System.in);
        int num = input.nextInt();
        int i = binarySearch(list, num);
        if(i >= 0)
        {
            System.out.println("Found " + list[i] + ". Its index is " + i);
        }
        else
        {
            System.out.println("Not found.");
        }
        input.close();
    }
    public static int binarySearch(int[] list, int key)
    {
        int low = 0;
        int high = list.length;
        //取数组最大位数为最大循环数
        while(high >= low)
        //这里是启用一个循环,循环内部是最大数和最小数
        {
            int mid = (low + high) / 2;
                //取中位数
            if(key < list[mid])
                //比较中位数和关键字的位置
            {
                high = mid - 1;
                    //缩小取值范围,将中位数的前一位数设置为最大值
            }
            else if (key == list[mid])
                //直到找到与关键字相匹配的中位数为止
            {
                return mid;
            }
            else
            {
                low = mid + 1;
            }
        }
        return -1;
    }

}

Sorting Arrays 选择排序

真的,当我看到老师放的这个视频的时候,我就知道已经没有说太多的必要了
直接点击视频就可以看了
一个视频胜过千言万语

那么问题来了,如何使用代码实现这个操作呢?
开整:

package selectionSort;

public class TestSelectionSort {

    public static void main(String[] args) 
    {
        int [] list = {34, 13, 5, 25, 56, 21, 59, 85, 2, 43};
        selectionSort(list);
        for(int i: list)
        {
            System.out.println(i + "");
        }
    }
    public static void selectionSort(int[] list)
    {
        for (int i = 0; i < list.length - 1; i++)
        {
            int currentMin = list[i];
            int currentMinIndex = i;
            for (int j = i = 1; j < list.length; j++)
            {
                if (currentMin > list[j])
                {
                    currentMin = list[j];
                    currentMinIndex = j;
                }
            }
            if (currentMinIndex != i)
            {
                list[currentMinIndex] = list[i];
                list[i] = currentMin;
            }
        }
    }
}

其实说到排序方法的话
还是用一个视频来讲比较好

这样子可以说简单明了了
(我感觉最后那个好好玩啊哈哈哈哈哈哈哈)
就有那种呜啦啦啦啦啦~的感觉

Chapter 8: Multidmensional Arrays

我们之前讲过一维数组,关于一维数组的概念这里就不BB啦
实在是记不得里的话可以向上看看

现在我们来讲讲二维数组

Introduction 简介

这个时候可能就有人要来问了,我们为啥要学这玩意列?
其实我也不知道(小声)

但柿!根据可靠消息,我们可以在以后用这个来处理矩阵
再往深奥一点的意义来讲的话
计算机图形学里面,一张图片的所有信息能用一个二维矩阵全部装下去
(我估计可能使用数字表示颜色,用二维矩阵来表示坐标像素点位置)
总之就是非常重要(扬声器最大声)

老样子我们先来看看二位数组的语法

double [] [] sample = {
    {2, 2},
    {2, 2}
};

这里有几点需要注意的

  1. 这里所使用的是两个 "[]"
  2. 记得里面的每行都需要用逗号结束
  3. 需要使用两个"{}"来将数字括起来
  4. 虽然和一维数组一样要以分号结尾但我感觉还是写出来比较好

一般的,我们使用两个中括号来表示这个是个二维数组

Two-Dimensional Arrays Basics 二维数组的入门到放弃

这里首先来讲讲数组的命名规则

int  [] [] matrix;//declare the matrix
matrix = new int [5][39];//fu zhi the matrix

二维数组的创建和一维数组的创建总是有无限的接近
不过后面那两个中括号可大有讲究
第一个中括号表示行
第二个中括号表示列
这个顺序是无法被改变的

哦对了,这里有个很坑的地方,就是
emmmmmmm......
得了我感觉我不懂怎么表达
还是用图片来说比较好

Two-dimensional Arrays

你看括号内的是5,但是这个数组最高的就是到4而已
因为数组是从0开始哒!

在看到上面那个图片的第三个数组
这个就是直接把创建个命名弄到一起去了
不过记得前面提到过的创建数组的几个点

那么如果我们想知道数组的长度呢?
这里可以使用
x.length
来获取

不过在二位数组里,我们不止想知道数组有多少行,还想知道数组有多少列呢?
这里可以用
x [0].length
来获取
简单的来说,想要多少行就直接用 x.length,想要多少列就直接用 x[0].length
我估计这玩意用在考试里肯定很酸爽

Ragged Arrays 锯齿状数组

Ragged Arrays

一张图片解决战斗
这个是说明如何创建这个数组的
并且这里说明了一个很重要的一点
**二位数组的每一行都可以是不一样的
他们每一行都是一个独立的一维数组**

不过可能有人说,不喜欢上面的这个创建的方法,希望能有更厉害的方法呢?
这里有个可以让代码看起来更厉害的方法

int[][] triangeArray = new int[5][];
triangleArray[0] = new int[5];
triangleArray[1] = new int[4];
triangleArray[2] = new int[3];
triangleArray[3] = new int[2];
triangleArray[4] = new int[1];

这样子其实达到的效果和上面那个是一样的
这里看到上面在定义数组的时候,多少列这里是留空的
也就意味着这玩意可以不写
我们在后面再去声明就可以了

我们可以通过一个小程序来简单的了解数组应该如何正确食用

package multi;
import java.util.Scanner;
public class TestArray {

    public static void main(String[] args) {
        //declare, create, assign
        //method 1
        int[][] matrix;
        matrix = new int[3][42];
    
        //matrix 2
        int [][] matrix2 = new int[3][43];
    
        //method 3
        int[][] matrix3 = {
                {1, 2},
                {3, 4},
                {5, 6}
        };
    
        //1. Initializing arrays with input by user
        Scanner input = new Scanner(System.in);
        System.out.println("Enter " + matrix.length + " rows and " + matrix[0].length + "colums interger numbers:");
        for (int i = 0; i < matrix.length ; i++)
        {
            for (int j = 0; j< matrix[0].length; j++)
            {
                matrix[i][j] = input.nextInt();
            }
        }
    
        //2.Printing arrays
        for (int i = 0; i < matrix.length ; i++)
        {
            for (int j = 0; j< matrix[0].length; j++)
            {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    
        //3. Summing all elements
    
        //4. Summing elements by column
        for (int column = 0; column < matrix[0].length; column++)
        {
            int total = 0;
            for(int row = 0; row < matrix.length; row++)
            {
                total = total + matrix[row][column];
            
            }
            System.out.println("The Sum of this column " + column + " is " + total);
        }
    }

}

Processing Two-Dimensional Arrays 把二位数组作为参数传递到不同方法中

emmmm.......
这玩意和一维数组的完全一样
感觉不想多BB了
直接看前面的把
pass by sharing的概念都是一样的

Chapter 9: Object and classes

之前咱们讲了半天,归根结底还是一句话

--找不到对象

这句话在现实中也是很实用的
(:з」∠)

Defining Class for Object 定义

Object-oriented programming (OOP) 对象编程

一个对象可以表示显示生活中的实体entity
这些实体都有一些独特的一些特征,比如状态之类的
虽然所有的猫都是猫,但是却不是同样的实体
比如CC的猫,所有的猫都有不同的猫
因为他们有一些特定的属性,一些特定的行为
比如最喜欢的是何物,毛发,年龄之类的
这就意味着每一个猫都是独一无二的对象
但是这些猫都属于同一个种类,这个就叫类Class

小狮子

数据域 data files
数据域用来表示这一个类所有的对象的属性

方法 Method
表示这一个类的对象的行为,也就是他所做的事情

一个对象拥有非常独特的特征,比如它会在晚上12点的时候起来去看看家里有没有老鼠
反正我是没见过抓老鼠的猫
可能我看的都是假猫

Class
记得我们之前说过,所有的猫都可以被定义为“猫”这个类
类是一个蓝图,是一个抽象的概念
它定义了有着相同属性的对象
而对象是类的一个实例

An object is an instance of a class

那么问题来了,是先有类还是先有对象呢?
答案是先有类
因为找不到对象...

好了言归正传,我们把用类转换为实例的过程称之为 实例化 Instantiation ,就是通过类来生成这么一些对象的这个过程

下面我们来看一个栗子

Object and methods

这是个关于几何图形的小程序,在未来很多的编程类型中,我们会基于这一个基础来发展开来
几何图形有很多种不同的类型,假如是一个特定的图形,那他们都会有一个相同的特征
今天我们先来看看圆形

看到上面的object 1、2、3,这3个方法都属于上面这个circle这个类
然后所有object中不同的区别就是在于圆的半径
这里圆的半径Radius叫做这个圆的数据域 data files

假如我们先创建出来一个小圆,当我们把这个圆放大的时候,实际的动作其实是改变这个圆的半径

假如我们需要计算这个圆的半径、周长,这里都是用方法来实现的

这里可能有人要问了,如何用代码来实现这个看起来很不错的功能呢?

class Circle
//这里注意,类的首字母需要大写
{
    //data fields or data members
    double radius;

    //constructors
    //default constructor
    Circle() 
    {
        radius = 1;
    }

    //the second constructor
    Circle(double newRadius)
    {
        radius = newRadius;
    }

    //methods
    double getArea()
    {
        return radius * radius * Math.PI;
    }
    double getPerimeter()
    {
        return 2* radius * Math.PI;
    }
    double setRadius(double newRadius)
    {
        radius = newRadius;
    }
}

这玩意感觉是C语言...

哦对了,有时候我们可能会看到一个玩意,叫UML
Unified Modeling Language (UML) 统一建模语言,一般会以缩写的形式存在
这玩意就是大家遵循这样的规则来对某个事情进行概括

UML

哦对了,这里有个玩意叫 Constructors 构造方法
A constructor is invoked to create an object using the new operator
构造方法是用来生成一个用来生成一个属于这个类的对象
类似于普通的方法一样,我们可以调用这个构造方法
但是调用构造方法的目的和作用就是生成一个属于这个类的对象

构造方法有3个特征:

  1. 构造方法的名字必须和类的名字一模一样,甚至连大小写也要一模一样
  2. 构造方法没有返回任何东西,甚至连void都不需要
  3. 当被其他方法被调用的时候,需要用 new 操作符来进行调用

那么可能有人要问了,这个有什么意义呢?
出现了!一意义怪!
其实我也不知道(摊手)
下节课再说呗

哦对了,当我们写完了程序之后,我们能在电脑中找到这个玩意的源文件
至于文件保存在什么地方的话,就是在创建的时候设置的地方
然后编译器也会把我们所写的源文件编写为.class文件
Java会直接去执行编译完成的.class文件而不会去执行java源文件

Via Reference variables

哦对了
不知道你注意到没有
前面那个代码,好像没有main
记得之前Cc说过,所有程序的开头永远是从main方法开始的
但是前面这个没有
那我们就需要再创建一个main方法出来
所以我们在上一个pacage内再创建一个class
取名为TestCircle(再提一次,类的首字母要大写)
然后这里就可以勾上最喜闻乐见的Main方法了

pacage circle;

public class TestCircle
{
    public static void main(String[] args)
    {
        //int radius;
        Circle circle1 = new Circle();
        //calling the constructor of Circle Class

        System.out.print(circle1.radius);
        System.out.println(circle1.grtAtea());
        System.out.println(circle1.getPerimeter());
        //get method form class Circle

        circle1.radius = 100;
        System.out.println(circle1.getArea());
        circle.setRadius(10000);
        System.out.println(circle1.getArea());
        //we can change the value in constructor

        Circle circle2 = new Circle(20.000);
        //calling the second construction of Circle Class
        System.out.print(circle2.radius);
        System.out.println(circle2.grtAtea());
    }
}

首先我们先把视线放在 Circle circle1 = new Circle(); 这一行上
先来对比这两行代码

int[] array = new int[10];
Circle circle1 = new Circle();

可以看到,和创建数组的语句类似,创建和引用构造方法是非常类似的
我们首先需要先声明这个是个什么类的,当然这个类是我们已经自定义的了

其实Circle circle1 = new Circle();这玩意可以拆分为两行

Circle circle1;
circle1 = new Circle();

当然这个和数组的也是非常类似
因为数组也能拆分为两行

int[] array;
array = new int[10];

然后circle1这个是可以自定义的名字,有个更专业的名字叫 Reference Vriable ,虽然专业名字更让人看不懂,但是这也不影响我们可以给circle1取什么名字都可以,但是要遵循命名规则
比如iLikeLion
首字母小写,其后每个单词首字母都需要大写
之后的那个new是一个特定的操作符,后面接着的是构造方法,用来生成一个对象
Circle() 表示调用 类 Circle 构造方法

这里有一点值得注意,当我们使用Circle(100)的时候,表示向方法中传递数字,这里就不会使用Circle()这个方法,而会使用
Circle(double radius)这个方法

这里我们引入一个概念: instance 实例的

对象是类的实例化

这个概念还是蛮重要的
举个栗子,instance vaiable实例变量 ,比如我们前面那个小程序中的半径就是实例变量
instance method 实例方法,比如我们前面的getArea方法,因为这个方法都是由某一个具体的对象所决定的
换句话说,当圆的半径改变的时候,getArea得出来的值也会随之改变

Call method from another package

假如有一天,我们想引入其他package里面的类甚至是类里面的方法,是否有这个操作呢
我们可以使用import 来实现这样的操作

这个 词我们之前也曾提到过
就是import java.util.Scanner这个

讲道理这两个东西真的是太相似了
举个栗子

Circle and Rectange

在上面这张图中,假如为我们想在rectange里调用circle里的东西呢
只需要使用

import circle.Circle;

就可以了

import     //导入
circle.    //来自package circle
Circle    //package circle 里的 类Circle

但是,当你引用了这个东西,它或许还会报错
毕竟报错就是java的灵魂
没有报错的java是不完成的java

这个是因为我们之前在写类Circle的时候,里面的构造方法没有设定为publie
简单的来说,如果不加public的话,这个method就是仅限内部员工使用的
当我们给类Circle的构造方法Circle() 加上public 之后,它应该变为这样

public Circle()
{
}

这样就没问题了

哦对了,虽然说一个Java源文件中能包含多个类,但是public这玩意也不能乱用

"one or more classes in one java file. But only one class coule be defined as 'public' "

  • 每个类里面只能有一个public

"the public class's name should be exactly same as the file name"

  • 有public的类必须和类的名字相同(就是左边那个列表里出现的类的名字)

"main() will be put inside a public class , public class is like a string point"

  • main()里的public是不可少的,也就是说在main方法所在的类必须要加public

" if there is no public class, then your main method coule be put in any one class. but if there is a public class, your main method must be in the public class"

  • 如果一个源文件中没有public类的话,那main()放在哪个类里面都是ok的。但是程序中有一个public类的话,主方法必须要放在public类里面

用一张图来总结类和对象的关系

对象和类

different between Cariables of Primitive Types and Reference Types

这里要撤回去一个概念,我们回到原始数据类型 primitive type
原始数据类型一共有8种,int, double ,float, char, boolean, byte, short, long
对于原始数据类型,我们为其赋值的时候,其实就是用所需要的的值去覆盖去替换掉原始数值
假设我们写了一条指令
int i = 1;
这个实际上就是在我们电脑内存中,有这么一个栈,这个栈存放了我们写这一行代码的信息
同时,int会被赋值为1,这也就意味着在电脑存放 i 这个位置的地方会被 1 所代表的值所取代

那么现在的类和对象的概念有啥不同呢
记得之前在第七章数组这个概念中,提到过数组的赋值方法是 pass by sharing
也就是箭头和仓库(地址)的问题(详情可以在右边找Chapter7 )
虽然数组会被赋值但是原始数组并没有消失,只是没有指向这个数组的标志了

其实类的在电脑桌存放的概念和数组非常相似
这玩意叫 Reference Type

Reference Type

当我们将c2的值赋值给c1的时候,c1将会指向c2所在的那个仓库(address)
但是实际上c1原来所指代的那个仓库还是保留在内存中的
我们改变的就是c1所指代的位置

Static Variables, Constants, Methods

static,静态的
static variables 静态的变量
static constant 静态的常量
static method 静态的方法

那么到底什么是静态的呢?
我们来举个例子,假如一群人去吃火锅,我往里面瞎了眼一份牛肉丸
那么这些肉丸大家都可以吃得到,因为我们是吃的同一个火锅 static
但是如果是一人一个小锅,我往我自己的锅里面下了一份牛肉丸,那么这一份牛肉丸就是我自己独有的 private
这里就是借助牛肉丸的概念来理解static的意思
static是能被所有对象共享的,所有的方法都可以访问它

Static

记得之前在写圆的面积周长啥的时候,我们有一个圆的半径,就是 π 这个玩意
π 需要被多个 method 共同使用,但是却没有任何东西能改变它的大小
这个时候, π 就是一个静态的常量 static constant
所以我们可以在代码的第一行中加入

final static double PI = 3.1415926;

来给定 π 的值
这样我们在后面的代码中就不需要使用math.PI了,就可以直接使用PI

接下来我们来看看静态的变量 static variables
假如我们需要一个变量来记录这个程序到底执行了多少次
虽然只需要使用count++就能解决的事情
但是这个变量还是有类型的
这个类型就是静态的变量
比如我们在执行完方法1后,使用count++来记录方法1执行的次数
这个时候我们去执行方法2,但是也使用count++来记录方法2的执行次数
在这里方法1和方法2使用的都是同一个count来记录的
这一个变量它不是仅仅依赖于某一个具体的源变量本身,而是被所有的源对象共享的
我们把这样的变量叫做 static variables
因为这个变量是被这个类所共享的,所以也能叫类变量 class variable

在创建静态变量的时候,我们可以使用

static int circleNumber = 0;

//如果我们最开始不定义其为0的话,它会默认赋值为int类的初始值,也就是0

说到static method, 感觉也挺简单的
这玩意创建的方法就是

static int getNumberObjects()
{
return numberOfObjects;
}

没了
不过值得注意的一点是,我们如果希望在UML中表示出这个方法是静态的方法的话,需要在其下加一条下划线
同样在变量中也是一样的,加了下划线的表示静态的变量
用图表示的话就像这样

static method

那么,对于静态的方法和实例的方法有什么区别呢?
简单的来说,实例的方法可以访问这个类的所有的方法和变量(数据域)
但是静态的方法被设计为只能访问静态的方法和变量(数据域),不能调用实例的方法和实例的变量

我们之前提到过,静态的变量是属于这个类的方法都可以访问的数据域,它的值可以被所有方法更改
而静态的方法就像是专业为静态变量而生的,它们会对这些静态的变量进行一系列的操作来打到目的
比如获得某个变量的值getNumber

而那些实例的变量来说,它们的值是随时都可以改变的
举个栗子,之前的圆的半径的问题
无论是圆1的半径还是圆2的半径,它们的值都是属于它们自己的,都不是共享的
所以去访问它的不应该是一个静态的方法,因为静态的方法是大家共享的一个方法
静态方法去访问一个实例变量的时候,由于实例变量往往是属于某一个方法的,在访问的时候可能会出现最喜闻乐见的话
“找不到对象”

那我们还是举个栗子吧

package classhomework;

public class ClassHomework {

    int i = 5;
    static int k = 2;

    public static void main(String[] args) 
    {
        int j = i;
        m1();

    }

    public void m1()
    {
        i = i + k + m2(i , k);
    }

    public static int m2(int i, int j)
    {
        return (int)(Math.pow (i, j));
    }

}

上面这个有没有问题咧
答案在下面

答案

package classhomework;

public class ClassHomework {

    int i = 5;
    static int k = 2;

    public static void main(String[] args) 
    {
        int j = i;
    //在这个方法前面,有个int i = 5
    //这也就意味着i是一个实例变量
    //但是这个方法里带有static字眼,表示这玩意是个静态方法
    //我们之前提到过,静态方法不能调用实例变量
    //所以我们这里是会报错的
        m1();
    //你看下面的方法m1中有没有static字眼
    //没错我也没找到
    //所以m1方法是个实例方法
    //然而这个主方法是个静态的方法
    //所以肯定是不行的

    }

    public void m1()
    {
        i = i + k + m2(i , k);
    //你看这里可是个实例方法哦
    //实例方法可调用一切
    }

    public static int m2(int i, int j)
    {
        return (int)(Math.pow (i, j));
    }

}

那么问题来了,如果说我一定要在静态方法里使用实例方法呢

package classhomework;

public class ClassHomework {

    int i = 5;
    static int k = 2;

    public static void main(String[] args) 
    {
        ClassHomework a = new ClassHomework();
    //这里其实就是将静态的方法指定为一个新的方法,然后再在其中作为新的变量插入
        int j = a.i;
        a.m1();

    }

    public void m1()
    {
        i = i + k + m2(i , k);
    }

    public static int m2(int i, int j)
    {
        return (int)(Math.pow (i, j));
    }

}

啊,这classhomework打的真是烦死了
下次起个短一点的名字

前情提要(关键词复习)

primitive type variables 原始数据类型变量
reference type variables 引用类型变量

static ( variable / constant / method ) 静态的 变量/常量/方法
static variable = class variable
static constant ---> final static datatype name
静态的方法和实例的方法是互相对比滴

access specifier 访问修饰符

写在前面:access specifier 访问修饰符 也可以写作 visibility modifiers 可见性修饰符

我们之前写代码的时候,第一条永远是
public static void main(String[] args)
但是好像没人问过这句话到底是啥意思
至少我是没问过的
因为老师肯定会讲嘛(摊手)

其实说起访问修饰符的话,一共是这4个
public 公共的
default 默认的
private 私有的
provate 被保护的

这四个单词都是用来表示某一个东西是否是可见的
说白了就是在另外一个地方能不能访问到它

这四个关键词都是用来修饰一个类的,或者是类内部的变量、方法之类的
当我们在写代码的时候,我们可以使用不同的可见性修饰符来定义它

比如我们之前在写圆这个代码的时候,我们可以使用不同的修饰符来修饰其中不一样的方法
一定要注意,这个能够放在类和方法的前面

首先我们先来看 public
public 和 static是不一样的
虽然说我们把使用static将方法设置为一个静态的方法
也就是所有对象都能够访问它
但是这并不意味着他是一个公开的
这两个单词所表示的范畴是完全不一样的

  • static 是只能够修饰方法,不能够修饰类的
  • static 的作用就是把某一个方法或者变量设定为当前类都能够访问,当这个变量的值改变的时候,会对当前类产生影响

  • public 当给一个类设定为公共的之后,对于其他的类而言,这个类是可见的 。举个栗子,我给圆这个类设定为public之后,当我创建一个长方形类的时候,对于长方形这个类来说,圆这个类是可见的。意味着在长方形类里面可以使用Circle cc = new circle; 去访问和调用圆类的代码来创建一个对象
  • public 假如我有一瓶肥宅快乐水,当我将这瓶肥宅快乐水设定为public之后,就意味着是共享肥宅快乐水了

  • default 当我们没对类进行详细定义的时候,也就是说类前面是个光头的时候,就意味着它会默认地使用default
  • default 并不用可刻意地写在方法前面,当我们没有这3个字的时候,它就会默认为default
  • default 当一个类被设定为default的时候,其会被默认为 package-private包内访问,也就意味着能够在一个包内互相访问。换句话说 ,隔壁包就无法被访问了

  • private 这玩意用来修饰类内部的变量或者方法,并不会修饰一个类
  • private 因为把类设定为私有的话好像就没啥意义了
  • private 可能就是用来保护啥东西了的

private 这里就不多BB了
感觉以后肯定是超级麻烦的茬
能咸鱼一天算一天

Private and public in UML

那么,在UML中又该怎么表示呢?
让我猜猜,肯定有人忘了UML是啥

UML答案--点开了自觉抄10遍

Unified Modeling Language 统一建模语言

其实也挺简单的
如果是private 的话就在方法前加个减号,就像 - 这样
反过来如果是public 的话就在方法前加个加号,就像 + 这样
整体来看的话就像这样
Private and public in UML

Data Field Encapsulation 数据域封装

这里说到了虫子(BUG)攻击
据说电脑BUG之所以叫BUG是因为最原始的电脑真的会被一直虫子搞的BUG出来

不过今天的可不像以前那样了
今天我们讲究安全性

当我们在写程序的时候,一般都要有一种意识,就是别人不能随随便便改我的程序
就算我留有接口给别人调用都好,但是本应该属于程序的变量时不会改变的
所以这里就涉及到一个东西,叫 Encapsulation 封装
说白了就是组装好了的机械,能够正常的去运行,但是你并不知道机械内部到底是什么歌情况,也不允许查看其中的东西

当我们在命名一些方法的时候,一般可以用 getter 和 setter 来对其进行命名
getter 就是当我们想获得一些私人的变量的值的时候,需要写的一个特定的方法来获得这个变量的值
setter 也是针对私有的数据域或者改变它的值,才会被称为setter

Passing Objects To Methods

其实我们可以通过一个小栗子来简单地理解

package circle;

public class TestPassCircle {

    public static void main(String[] args) {
        Circle cc = new Circle(10);
        int n = 5;
        printAreas(n , cc);
        System.out.println ("After calling method:");
        System.out.println("Radius is " + cc.getRadius());
        System.out.println("n is " + n);
    }
    public static void printAreas (int times, Circle c)
    //先看到这里的这个Circle C
    //我们需要在这个方法中接受一个来自类 Ciecle 的对象(c 变量为属于类Circle )
    //这里感觉就像是拿了一个Circle的变量来用,还是原封不动的那种
        {
            System.out.println("Radius \tArea");
            while(times >= 1)
            {
                System.out.println(c.getRadius() + "\t" + c.getArea());
                c.setRadius(c.getRadius() + 1);
                times--;
            }
            System.out.println("Radius is " + c.getRadius() + "\n");
     }
    
    }

这玩意输出结果虽然有蛮多的,但是真正重要的就三行

balabalabala
Radius is 15.0

After calling method:
Radius is 15.0
n is 5

这里可真正体现了 pass-by-value 的精髓了

你看变量n
最开始我们传递过去的时候,它的值是5
这个在传递的时候,是把变量的值,也就是10传递了过去,而不是传递变量本身
变量本身的值还是不会改变的
在方法内部n的值因为循环的原因每一次都在改变
但是无论n的值如何改变,主方法里n的值永远不会改变,也就是不会影响到主方法里的

这里得和数组在方法之间的传递区分开来
我这里就不写出来了不然看着也乱
数组就是pass-by-Sharing
具体是啥就回到数组哪儿去看看吧

array of object

记得在之前的时候,我们讲过如何创建一个int类型的数组

int[] arrayName = new int[ 10 ];

那么你可能猜到了,为啥要在讲对象的时候提到这个数组列
当然是因为我们有了这个对象数组啦
和int类型的数组一样,这个也能被简单地创建出来

Circle[] circleArray = new Circle[10];

对比一下之前的那个,是不是非常的相似?
当这个语句运行完成之后,系统就会自动分出一个 Heap 堆 来存放这个玩意
只不过这个里面还是空的,也就是空值
因为在这个时候数组确实是用来存放Circle类的对象,但是这个时候还没被创建出来
所以这个时候我们需要使用一个循环来生成它们
这里要注意是生成生成,不是像之前那样的直接赋值
举个栗子

for(int i = 0; i < circleArray.length; i++)
{
    circleArray[i] = new Circle(5);
}

那么为啥之前交生成它们呢?
因为这个数组我们在做的其实是单纯的付给它一个 reference variables
就是给它了一个小仓库的地址
这样子数组就能够在每个位置指向属于它自己的仓库了

Array of object

The Scope of Variable 变量的作用域

我们之前确实讲过变量的作用域
这里之所以再讲一次是因为

一个类的代码包含两大部分,一个是这个类的数据成员 data fileds (或者可以叫类的变量 class's variables)
第二个部分是类的行为,就是类的对象的行为

不过值得一提的是,当在类里面使用变量的时候,就算先用后声明也是ok的
这些数据域的成员可以放在整个类的任何一个地方
可以是最开始也可以是最后面都是ok的
举个栗子

public class Circle
{
    public double findArea() 
    {
        return radius * radius * Math.PI;
    }
    private double radius = 1;
}

你看在上面这个例子中,方法findArea位于类Circle中
但是我们是先用再声明
这样也不会报错的
但是有个问题要注意一下

我们来看这样一个例子

public class F 
{
    private int i;
    private int j = i + 1;
}

如果是这样的话它就会报错
因为j的值是基于i的值的
所以在这种情况之下就不能交换它们之间的位置

在这里老师引入了一个很有趣的小栗子
这个栗子可以充分帮助我们理解变量的作用域的问题

public class Test {
    private static int i = 0;
    private static int j = 0;

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int i = 2;
        int k = 3;
        {
            int j = 3;
            System.out.println("i + j is " + i + j);
        }
    
        k = i + j;
        System.out.println("k is " + k);
        System.out.println("j is " + j);

    }

}

小栗子答案

首先先来说说答案

i + j is 23
k is 2
j is 0

如果能正确地说出答案的话那就没必要看解析啦
当然为此一次就是没做对滴
很绝望
那个 i + j 根本不按套路出牌
过分了过分了

public class Test {
    private static int i = 0;
    private static int j = 0;
    //这里的叫做类的变量class's variables
    //上面讲过,这句话无论放在这个类的前面和后面效果都一样的

    public static void main(String[] args) {

        int i = 2;
        int j = 3;
            //这里的就是考点了
            //这里的两个变量,如果在eclipse里面输入的话,会发现它两的颜色和上面的类变量不一样
            //因为他们两个的作用域不同
            //这两个的作用域就是仅仅限于这个block 块的
            //我们可以看到,优先级还是以方法内的优先
            //就算外面有个类变量,方法内的变量还是被优先考虑的
        {
            int j = 3;
                    //老师说过,变量的作用域表示的就是它所在的这个块 block 
                    //然而区分每个块的标志就是花括号
                    //这里会优先以 j = 3 来计算
            System.out.println("i + j is " + i + j);
        }
    
        k = i + j;
            //在上面的 j = 3 的作用域已经完成,这里就不属于它的作用域了
            //所以我们往上找找,剩下的就只是类变量里的 j = 0了
            //所以在这里j的值应该为0
        System.out.println("k is " + k);
        System.out.println("j is " + j);

    }

}

The this reference

接下来我们来讲一个关键字,这个
就是这个
“这个”
this

this表示的就是某个变量
其实我们平时在写代码的时候都没写 this 这个关键字,是因为Java自动帮我们加上去了
因为每个变量都得写这玩意的话看着都烦
当然写上才是正确的姿势
那么这个时候可能有人会问了,有什么意义呢
还真有些时候必须要自己写上

private double radius;
public void setRadius (double radius)
{
    radius = radius;
}

你看这里就是个小栗子
虽然这样子确实是不会报错
但是会有一个警告
因为Java根本不知道到底左边的是啥右边的是啥
这个时候就需要加个this了
我们将赋值语句改为

this.radius = radius;

用来表示左边的这个是我们类的变量半径,右边的是接收到的

哦对了this还有个很高端的操作
因为它在类里面可以指代这个类本身
比如我们需要调用这个类的构造方法的时候,我们就会使用

Circle(10);

但是用this来表示的话,可以写成这样

this(10);

表示的效果都是一样的

Chapter 10: Object-Oriented Thinking

Class absraction 类的抽象
class encapsulation 类的封装
我们在用很多方法的时候,很多时候我们都不知道这玩意到底该怎么用的
就是只知道怎么使用就行了

其实在Java世界里,所有的对象所有的方法都是会被写在类里面的
我们在写代码的时候往往都会先定义一个类出来
然后我们再在类里面去写代码

所以我们之前讨论到的方法的抽象和封装实际上就是类的抽象和封装

结束语

在这里感谢抽出宝贵时间帮我检查笔记的CC Teacher~

感谢网页没有在我码字到一半的时候崩溃
感谢我的小博客
感谢自己高中买的咖啡豆还能喝还没过期

还要感谢小狮子!!!
小狮子天下第一!!!!

  • ----to be continue
Last modification:August 3, 2023
如果觉得我的文章对你有用,请随意赞赏