方法
语句块
语句块 (也叫复合语句) 。
语句块中定义的变量只能用于自己,外部不能使用。
//(即语句块可以使用外部的变量,而外部不能使用语句块的变量)
public class Test19 {
public static void main(String[ ] args) {
int n;
int a;
{
int k;
int n;//编译错误: 不能重复定义变量 n
} //变量 k 的作用域到此为止
}
}
方法
方法(method):一段用来完成特定功能的代码片段, 类似于其它语言的函数(function)。
方法用于定义该类或该类的实例的行为特征和功能实现。
面向过程中, 函数是最基本单位, 整个程序由一个个函数调用组成。面向对象中, 整个程序的基本单位是类, 方法是从属于类和对象的。
方法的重载(overload)
重载: 一个类中可以定义多个名称相同, 但形式参数列表不同的方法。(重载的方法实际是完全不同的方法,只是名称相同而已)
构成方法重载的条件:
- 形参列表不同的含义: 形参类型、形参个数、形参顺序不同
- 只有返回值不同不构成方法的重载 如: int a(String str){}与 void a(String str){}不构成方法重载
- 只有形参的名称不同, 不构成方法的重载 如: int a(String str){}与 int a(String s){}不构成方法重载
【示例】方法重载
public class Test21 {
public static void main(String[ ] args) {
System.out.println(add(3, 5));// 8
System.out.println(add(3, 5, 10));// 18
System.out.println(add(3.0, 5));// 8.0
System.out.println(add(3, 5.0));// 8.0
// 我们已经见过的方法的重载
System.out.println();// 0 个参数
System.out.println(1);// 参数是 1 个 int
System.out.println(3.0);// 参数是 1 个 double
}
/** 求和的方法 */
public static int add(int n1, int n2) {
int sum = n1 + n2;
return sum;
}
// 方法名相同, 参数个数不同, 构成重载
public static int add(int n1, int n2, int n3) {
int sum = n1 + n2 + n3;
return sum;
}
// 方法名相同, 参数类型不同, 构成重载
public static double add(double n1, int n2) {
double sum = n1 + n2;
return sum;
}
// 方法名相同, 参数顺序不同, 构成重载
public static double add(int n1, double n2) {
double sum = n1 + n2;
return sum;
}
//编译错误: 只有返回值不同, 不构成方法的重载
public static double add(int n1, int n2) {
double sum = n1 + n2;
return sum;
}
//编译错误: 只有参数名称不同, 不构成方法的重载
public static int add(int n2, int n1) {
double sum = n1 + n2;
return sum;
}
}
practice:
定义一个方法处理公司的迟到问题:
(1) 输入: 迟到时间, 月薪。
(2) 处理逻辑:
1 迟到 1-10 分钟, 警告。
2 迟到 11-20 分钟, 罚款 100 元。
3 迟到 21 分钟-30 分钟, 罚款 200 元。
4 迟到 30 分钟以上, 扣除半日工资。
5 迟到 1 小时以上, 按照旷工计算, 扣除 3 日工资。
(3) 输出: 罚款金额
public class TestMethod2 {
/**
* (1)输入参数:迟到时间,月薪。
* (2)处理逻辑:
* ①迟到1-10 分钟,警告。
* ②迟到11-20 分钟,罚款100 元。
* ③迟到21分钟-30 分钟,罚款200 元。
* ④迟到30 分钟以上,扣除半日工资。
* ⑤迟到1小时以上,按照旷工计算,扣除3 日工资。
* (3)输出罚款金额
*/
public static int late(int lateMinute,double salary){
int fakuan = 0; //罚款
if(lateMinute<11){
System.out.println("警告! !不能迟到!!");
}else if(lateMinute<21){
fakuan = 100;
}else if(lateMinute<31){
fakuan = 200;
}else if(lateMinute<61){
fakuan = (int)(salary/(21.75*2)); //21.75 指的是:月平均工作日
}else{
fakuan = (int)(salary*3/(21.75));
}
System.out.println("迟到时间:"+lateMinute+",罚款: "+fakuan);
return fakuan;
}
public static void main(String[] args) {
late(45,42000);
}
}
递归结构
递归的基本思想就是“自己调用自己”。像深度优先搜索 ( DFS:Depth First Search) 等很多算法里都有用到。
递归结构包括两个部分:
口 定义递归头。 解决: 什么时候不调用自身方法。如果没有头, 将陷入死循环, 也就 是递归的结束条件。
口 递归体。 解决: 什么时候需要调用自身方法。
【示例】使用递归求 n!
public class Test22 {
public static void main(String[ ] args) {
long d1 = System.curentTimeMilis();
factorial(10);
long d2 = System.curentTimeMilis();
System.out.printf("递归费时:" +(d2-d1)); //耗时: 32ms
}
/** 求阶乘的方法*/
static long factorial(int n){
if(n==1){//递归头
return 1;
}else{//递归体
return n*factorial(n-1);//n! = n * (n-1)!
}
}
}
【示例】使用循环求 n!
public class Test23 {
public static void main(String[ ] args) {
long d3 = System.curentTimeMilis();
int a = 10;
int result = 1;
while (a > 1) {
result *= a * (a - 1);
a -= 2;
}
long d4 = System.curentTimeMilis();
System.out.println(result);
System.out.printf("普通循环费时: " + (d4 - d3));
}
}
递归的缺陷
算法简单是递归的优点之一。
但是递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环慢的多,所以在使用递归时要慎重。
上面示例中递归和循环的运行结果对比
面向对象编程(Object Oriented Programing)
表格结构和类结构
雇员类和雇员表的结构完全一样。只不过,雇员类增加了数据的类型而已。
-表格的动作和类的方法
-对象对应“表中的行数据”
在面向对象编程中,下面三句话记住:
- 表结构对应:类结构
- 一行数据对应:一个对象
- 表中所有数据对应:这个类的所有对象
//下面的四行数据,我们使用四个对象就需要这样表示(假设有对应的构造方法, 如下代码是示意,非真实代码):
emp1 = new Employee(ID:1001, name:"高小一", job:"程序员", baseSalary:20000, salary2:0, hiredate:"9 月 1 日", address:"北京");
emp2 = new Employee(ID:1002, name:"高小二", job:"前台", baseSalary:5000, salary2:0, hiredate:"9 月 2 日", address:"北京");
emp3 = new Employee(ID:1003, name:"高小三", job:"销售员", baseSalary:3000, salary2:15000, hiredate:"9 月 1 日", address:"郑 州");
emp4 = new Employee(ID:1004, name:"高小四", job:"财务", baseSalary:5000, salary2:0, hiredate:"9 月 2 日", address:"上海");
面向过程和面向对象思想
面向过程适合简单、不需要协作的事务,重点关注如何执行。
面向对象可以帮助我们从宏观上把握、从整体上分析整个系统。【面向对象(Oriented-Object)思想更契合人的思维模式。我们首先思考的是“怎么设计这个事物?”但具体到实现部分的微观操作(就是一个个方法),仍然需要面向过程的思路去处理。】
-面向过程和面向对象的区别
·面向对象和面向过程思想的总结
都是解决问题的思维方式,都是代码组织的方式。
面向过程是一种“执行者思维”,解决简单问题可以使用面向过程。
面向对象是一种“设计者思维”,解决复杂、需要协作的问题可以使用面向对象。
面向对象离不开面向过程:
宏观上:通过面向对象进行整体设计
微观上:执行和处理数据,仍然是面向过程。
面向对象是“设计者思维”
面向对象是一种“设计者思维”。
设计时,先从问题中找名词,然后确立这些名词哪些可以作为类,再根据问题需求确定的类的属性和方法,确定类之间的关系。
-面向对象分析: 写诗
先从场景中找出名词,以使用表格来表示。
分析完上面这些 Object 后,我们需要进行组合。把这些 Object 融合到一个场景。
-面向对象分析: 写小说
写小说本质上和设计软件是一样的,根据想要表达的内容,设计不同的场景、设计不同 的任务。
设计完成后,作者再按照一章一章的完成写作(执行阶段)。
以短篇小说《茶馆》为例,简单分析“面向对象设计方式写小说”的过程
-
明确小说主要内容和目标
-
人物设计分析
-
整体事件设计
-对象的进化史(数据管理和企业管理共通之处)
总结
对象说白了也是一种数据结构(对数据的管理模式),将数据和数据的行为放到了一起。
在内存上,对象就是一个内存块,存放了相关的数据集合!
对象的本质就一种数据的组织方式!
-对象和类的详解
类:class。
对象:Object,instance(实例)。(以后我们说某个类的对象,某个类的实例,是一样的意思)
类可以看成一类对象的模板,对象可以看成该类的一个具体实例。
类是用于描述同一类型的对象的一个抽象概念,类中定义了这一类对象所应具有的共同的属性、方法。
类的定义
【示例】类的定义方式
// 每一个源文件必须有且只有一个public class,并且类名和文件名保持一致!
public class Car {
}
class Tyre { // 一个Java文件可以同时定义多个class
}
class Engine {
}
class Seat {
}
对于一个类来说,有三种成员:属性 field、方法 method、构造器 constructor。
-属性 (field 成员变量)
属性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。 在定义成员变量时可以对其初始化,如果不对其初始化,Java 使用默认的值对其初始化。
属性定义格式:
[修饰符] 属性类型 属性名 = [默认值] ;
-方法
方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
[修饰符] 方法返回值类型 方法名(形参列表) {
// n 条语句
}
【示例】编写简单的学生类
public class SxtStu {
//属性(成员变量)
int id;
String sname;
int age;
//方法
void study(){
System.out.println("我正在学习!");
}
//构造方法
SxtStu(){
}
}
简单内存分析(帮助理解面向对象)
-构造方法(构造器 constructor)
构造器用于对象的初始化,而不是创建对象【构造方法是负责初始化(装修),不是建房子】
声明格式:
[修饰符] 类名(形参列表){
//n 条语句
}
构造器 4 个要点:
构造器通过 new 关键字调用!!
构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return 返回某个值。
如果我们没有定义构造器,则编译器会自动定义一个无参的构造方法。如果已定义 则编译器不会自动添加!
构造器的方法名必须和类名一致!
practice:
定义一个“点”(Point)类用来表示二维空间中的点(有两个坐标)。要求如下:
可以生成具有特定坐标的点对象。
提供可以计算该“点”距另外一点距离的方法
class Point {
double x, y;
public Point(double _x, double _y) {
x = _x;
y = _y;
}
public double getDistance(Point p) {
return Math.sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
}
public static void main(String[ ] args) {
Point p1 = new Point(3.0, 4.0);
Point origin = new Point(0.0, 0.0);
System.out.println(p1.getDistance(origin));
}
}
构造方法的重载
构造方法也是方法。与普通方法一样,构造方法也可以重载
【示例 】构造方法重载(创建不同用户对象)
public class User {
int id; // id
String name; // 账户名
String pwd; // 密码
public User() {
}
public User(int id, String name) {//如果方法构造中形参名与属性名相同时,需要使用 this 关键字区分属性与形参。 this.id 表示属性 id;id 表示形参 id
this.id = id;
this.name = name;
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public static void main(String[ ] args) {
User u1 = new User();
User u2 = new User(101, "大嗲嗲");
User u3 = new User(100, "小嗲嗲", "123456");
}
}