方法用于封装一段特定的逻辑功能,如执行计算或操作;方法可以在程序中反复被调用,方法可以减少代码的重复,便于程序的维护。
定义方法的5个要素是:修饰符、返回值类型、方法名、参数列表、方法体
语言格式如下:
<修饰符><返回值类型><方法名>(参数){
//方法体代码
}
下面程序中除了定义主方法以外,还定义了其他方法,代码如下:
package day01;
public class Text {
//main方法,无返回值
public static void main(String[] args) {
}
//自定义方法
//定义无返回值(void),表示方法执行以后没有返回值,无参数方法
void say() {};
//定义无返回值有参数的方法
/*
* print() 方法名后添加了一个String类型的声明,这是一个形参。
* 表示若要调用print方法,必须要传入一个参数(实参)给print方法。
*/
void print(String name) {};
//定义有返回值,有参数的方法
//sum方法面前的int表示返回类型,代表该方法执行完以后会返回(return)一个int的值
int sum(int sum1,int sum2) {
//return 返回值方式,返回 sum1+sum2
return sum1+sum2;
};
//以上三种都是无修饰符,表明修饰符不是方法必须的
/*
* 在有返回值类型的方法中,关键字 return 用于返回一个值给调用者;
* 在无返回值(void)中也可以使用 return 表示结束方法
*/
}
定义方法是需要注意 一下语法要求:
**(1) ** 一个方法必须要声明返回值类型(构造方法除外)。若方法不返回任何结果,则需要声明返回值类型为void.
(2) 方法在声明时必须指定返回值的类型,若方法不需要返回数据,将返回值类型声明为void;若方法需要返回数据,将返回值类型声明为特定的数据类型(设置为与返回数据类型相同),可通过return语句返回。return 语句的作用在于结束方法且将数据返回调用方
**(3) ** 若想在 main 方法中直接调用 A 方法,则A方法必须声明 static(静态)
(4) 方法的参数是指,在调用时传递给方法需要被方法处理的数据。方法可有参数,也可没有参数。有参数更加灵活
在定义方法时,需要声明该方法所需要的参数变量
在调用方法时,会将实际的参数值传递给方法的参数变量,必须保证传递参数的类型和个数符合方法的声明
方法调用的语法格式:
方法名([参数类型1 参数1,参数类型2 参数2,....]);
方法调用时需要注意:
(1) 方法调用时,传给被调用方法的实参类型需要和方法定义的形参类型匹配
(2) 方法调用语句所处的上下文环境要和方法定义的返回值类型匹配
(3) 如果在主方法(main)中直接调用自定义方法,方法需要关键字 static
package day01;
//创建Room类
public class Room {
static String[][] rooms = new String[12][10];
/*构造无参函数初始化数组*/
public Room() {
int i=0;
for(i=0;i<rooms.length;i++) {
for(int j=0;j<rooms[i].length;j++) {
rooms[i][j] = "empty";
}
}
}
/*查询所有房间*/
public static void search() {
int i=0;
int j=0;
for(i=0;i<rooms.length;i++) {
for(j=0;j<rooms[i].length;j++) {
System.out.println(rooms[i][j]+" ");
}
if(j%10==0) {
System.out.println("\n");
}
}
}
/*某客人入住某房间*/
public static void inRoom(String name,int room) {
int i=room/100;
System.out.println(i);
int j=room%100;
System.out.println(j);
rooms[i-1][j-1] =name;
}
/*某房间退房*/
public static void outRoom(int room) {
int i=room/100;
int j=room%100;
rooms[i-1][j-1] ="empty";
}
}
package day01;
import java.util.Scanner;
public class Room01 {
public static void main(String[] args) {
Scanner sca = new Scanner(System.in);
//创建实例化对象调用Room类
Room r = new Room();
while(true) {
System.out.println("请输入命令:");
String comm = sca.next();
if(comm.equalsIgnoreCase("search")) {
r.search();
}else if(comm.equalsIgnoreCase("IN")) {
System.out.println("输入姓名:");
String st = sca.next();
System.out.println("输入房间号:");
int in = sca.nextInt();
r.inRoom(st,in );
}else if(comm.equalsIgnoreCase("out")) {
System.out.println("请输入退房房间号:");
int in = sca.nextInt();
r.outRoom(in);
}else if(comm.equalsIgnoreCase("EXIT")) {
break;
}else {
System.out.println("无效命令,请重新输入!");
}
}
}
}
Java 中的构造器也叫构造方法,构造方法和一般普通定义的方法有很大区别,主要如下:
(1) 构造声明在类的内部
(2) 构造方法名字和类名必须一样
(3) 构造方法不能有返回类型
(4) 构造方法可以包含参数
具体如下:
package day01;
public class Class02 {
public static void main(String[] args) {
// new per() 内的参数传入构造方法,再传给类的实参
per pe = new per("zbt",42);
pe.sca();
}
}
class per{
//定义实参
private String name;
private int age;
//构造有参(形参)per方法
public per(String name,int age) {
//this.XXX 方法用来访问本类的成员方法
this.name=name;
this.age=age;
}
//这里没有使用Static ,因为静态Static中不能使用this. 两者存一
public void sca() {
System.out.println("姓名:"+this.name+"\n年龄:"+this.age);
}
/*
static void sca() {
System.out.println("姓名:"+name+"\n年龄:"+age);
}
这样写会出现报错,因为name,age是非静态字段
不能对非静态字段名进行静态引用(static)
*/
}
this 是对当前对象(this引用的是类的实例化对象,例如如下代码)的引用,是运行期间当前对象本身
(1) 可以使用 this 明确的访问当前对象的属性或者方法,类似于“我”
(2) this() 可以调用本类的其他构造器,可以实现构造器的重用,简化代码
(3) this() 必须写在构造器的第一行
具体代码如下:
public class Class01 {
public static void main(String[] args) {
Point per = new Point(5);
}
}
class Point{
int x;
int y;
public Point(int x) {
//调用本类的构造器
this(x,x);
}
//被调用
//这里的this表示的是per
public Point(int x,int y) {
this.x = x;
this.y = y;
System.out.println(x+y);
}
}
//运算结果:10
一个类中可以定义多个同名但参数类型不同的方法,这种语法叫做方法的重载。
方法重载就是方法名字一样但是方法参数不同,方法参数不同包括参数类型或者参数个数不同。
构造方法就是构造方法中的参数个数或者类型不同
public class Point{
int x;
int y;
public Point(int x) {
//调用本类的构造器
this(x,x);
}
//被调用(构造器)
public Point(int x,int y) {
this.x = x;
this.y = y;
}
}
上述代码中有两个构造方法:第一个构造方法中有一个 int 类型的参数,第二个构造方法中有两个 int 参数的类型,这就叫构造方法的重载。
构造方法重载即写多个参数不一样的构造器。
构造方法重载就是为了实现构造方法的重用。
Java 类中一定有构造器,当使用new关键字时,JVM 必定会调用构造器创建对象
如果类中没有声明任何构造器,javac 会自动提供一个构造器,代码如下:
public class Class01 {
public static void main(String[] args) {
foo f = new foo();
}
}
class foo{
//public foo(){}自动提供一个默认构造器
}
当 class 中没有声明构造器时,javac 会自动提供一个无参数的构造器,代码如下:
public class Class01 {
public static void main(String[] args) {
foo f = new foo();
Goo g = new Goo(2);//调用构造Goo(int)
}
}
class foo{
//默认构造器
}
class Goo{
int a;
//如果定义了构造器,javac不再提供默认构造器
public Goo(int a) {
}
}
注意:如果 class 没有声明构造器,javac 会提供一个无参数的构造器,但是如果用户定义了构造器,无参数构造器就不会被自动提供,如果要使用无参数构造器,则需要自己定义
方法是动作、功能,一般用动词声明,下例代码是求点到原点之间的距离:
package day01;
public class Class01 {
public static void main(String[] args) {
Point p = new Point();
double b = p.distance(1,2);
System.out.println(b);
}
}
//不能用Public修饰,因为公共类型点必须在其自己的文件中定义
class Point{
private int x;
private int y;
public Point() {
}
public double distance(int x,int y) {
this.x=x;
this.y=y;
//返回值返回给调用者(double b)
return Math.sqrt(this.x*this.x+this.y*this.y);
}
}
方法名一样,参数不一样,重载体现了功能的多样性,重载的方法经常互相重用
//Point类是一个点类,在java.awt中
public class Point {
int x;
int y;
public Point(int x){
//因为构造器的名称都相同,所以调用本类中的构造器时只需要设置参数即可
//调用其他方法则要引用方法名
//调用本类中的构造器
//this()必须放在构造器第一行
this(x,x);
}
//构造器
public Point(int x,int y) {
this.x=x;
this.y=y;
}
//计算当前点到原点的距离
public double distance() {
return Math.sqrt(this.x*this.x+this.y*this.y);
}
//方法重载(方法名一样,参数列表不同)
//计算当前点(形参点)到原点(定义点)的距离
public double distance(int x,int y) {
return Math.sqrt((this.x-x)*(this.x-x)
+(this.y-y)*(this.y-y));
}
//重载方法之间经常重用
public double distance(Point other) {
return Math.sqrt(distance(other.x,other.y));
}
}
构造方法的重载:定义类中的构造器(多个),同名不同参数
方法的重载:定义类中的方法(多个),同名不同参数
方法的重写:继承中的子类,重写父类中的方法,同名同参数
Java 方法参数的传递规则:基于值的传递
Java 方法参数传递只有一种方式,基于值的传递,是变量值的复制,基本类型就是其中值的复制,引用数据时应用值(地址)的复制。
如下代码所示:
//涉及到程序内存分析
public class Class01 {
public static void main(String[] args) {
int a=1;
add(a);
Koo koo = new Koo();
add(koo);
System.out.println(a+","+koo.a);//1,2
System.out.println(koo);//day01.Koo@2f92e0f4
}
//参数是基本类型
public static int add(int a) {
a++;
//方法返回,回收临时变量
return a;
}
//参数是引用类型
public static int add(Koo koo) {
Koo k = koo;
k.a++;
//方法返回,回收临时变量
return koo.a;
}
}
class Koo{
int a = 1;
}
我们定义的类可以继承自某个已经存在的类,这样就可以复用已经存在类的代码(属性和方法)。在继承的关系中,被继承的类叫做父类,继承的类叫做子类
子类除了能自动继承父类的属性和方法外,还可以定义自己的属性和方法
如果我们没有声明父类,则默认父类是 java.lang.Object类 ,因此 Object 类是 java 类中所有类的直接或间接父类
在 java 语言中通过 extends 关键字继承一个类,被继承的称为父类,继承的类称为子类,如果子类继承了一个父类,就继承父类中非私有属性和方法
例如如下代码:
//定义一个public类
public class Class01 {
//Class01类的私有类,不可以被继承
private String name;
int age;
String set;
}
//继承,共享被继承类的属性和方法
class Student extends Class01{
double score;
}
//继承
class Teacher extends Class01{
double sal;
}
注意:在 java 中只支持单继承,也就是一个子类只能有一个父类,但是一个父类可以有多个子类.
我们可以在子类中定义和父类中同名同参数的方法,这种语法叫做方法的重写。
方法的重写需要满足如下条件:
(1) 子类方法与父类方法同名
(2) 子类方法与父类方法同参数(参数个数、类型和顺序都相同)
(3) 子类方法的访问控制修饰符不能比父类方法的更封闭
方法覆盖有其现实意义,它表示父子类都具有某种行为,但这种行为的执行方式各不相同。同时,方法覆盖也是有实现对象多态的基础。
方法覆盖的实现,如下代码:
//定义一个public类
public class Class01 {
String name;
int age;
String set;
//构造方法
public Class01() {
}
public void move() {
System.out.println("父类中的move方法");
}
}
//继承,共享被继承类的属性和方法
class Student extends Class01{
double score;
public Student(){
super();//调用父类无参构造
}
//父类方法的重写
public void move() {
System.out.println("子类重写后的方法");
}
}
上述代码中,子类重写了父类中的move方法。方法重写后,用子类对象调用该方法,执行的是重写后的方法。
关于多态的概念,可以理解为两层含义:
(1) 方法的多态:若在一个类中定义有多个方法的重载(同名不同参),在调用这些方法时,通过传递不同的参数来调用不同的方法。这就好像我们调用一个方法会有多种不同的表现
(2) 对象的多态:一个对象可以有多种形态,既可以当作本类的对象来看,也可以当做其父类对象来看。我们可以把一个对象当做它的父类对象来看,也就是定义父类的引用得到子类的对象,如下:
// a 是子类 Student 的对象
Class01 stu = new Student();
上述代码中,只能使用这个变量去访问父类中所定义的成员(子类父类共有的方法和属性)。而不能去访问子类中特有的成员。因此,具体如下:
public class Class02 {
public static void main(String[] args) {
//子类的对象stu
Class01 stu = new Student();
//访问合理
stu.move();
//访问不合理,只能访问父类已经定义的,而test在父类中没有定义
stu.test();
}
}
//定义一个public类
public class Class01 {
//被共享
String name;
int age;
String set;
//构造方法
public Class01() {
}
public void move() {
System.out.println("父类中的move方法");
}
}
//继承,共享被继承类的属性和方法
class Student extends Class01{
double score;
//父类方法的重写
public void move() {
System.out.println("子类重写后的方法");
}
public void test() {
}
}
之前讲到构造器是在创建对象的时调用的,理解继承的概念后,再讲解构造器,在继承中子类的构造器一定调用父类构造器
例如如下代码:
/*
继承中的构造器调用
子类一定调用父类构造器
子类默认调用父类默认构造器
*/
public class Class02 {
public static void main(String[] args) {
}
}
class Foo{
public Foo() {
}
}
class Koo extends Foo{
public Koo() {
super();//super()的作用就是调用父类中的无参数构造器,super指的是父类对象,必须子类构造器放在第一行
}
}
在继承时,要注意以下几点:
(1) 子类构造器默认调用父类无参数构造器
(2) super() 表示调用父类构造器
(3) 使用 super() 调用父类构造器,必须放在子类构造器的第一行
**(4) ** this() 必须放在子类构造器的第一行
(5) this() 和 super() 两者互斥。有我无你
同时,如果父类中没有无参数构造器就会出现编译错误。当出现这种问题时,解决方法如下:
class Foo{
int a;
public Foo(int a) {
this.a = a;
}
}
//class Koo extends Foo{} 编译错误,子类Koo找不到父类无参构造器
class Koo extends Foo{
public Koo() {
super(2);//调用父类有参构造
}
}
//super(2)中的 整数2 对应的是父类中有参构造器中的 int 类型
//如果是父类中有参构造器中是 String 类型,则super()中要指明的是 String 类型
在编译时要注意:
(1) 如果父类没有无参构造器,就必须在子类中明确指定调用父类的有参构造器
(2) 编程建议,所有类都提供无参数构造器,减少继承时候的麻烦
this 和 super 关键字的用法类似,总结如下:
关键字 | 出现的位置 | 代表含义 |
---|---|---|
this | 构造方法第一行/this.(); | 调用本类其他构造器 |
方法代码的其他位置/this.name; | 访问当前对象的成员 | |
super | 构造方法第一行/super(); | 调用父类构造器 |
方法代码的其他位置/super.name; | 访问父类对象的成员 |
(1) 任何构造方法的第一行必须是this();或者super();的调用,如果没有明确调用,则系统会默认加上super();调用
(2) this(); 和 super();只能出现在构造方法的第一行位置
使用 static 声明的方法,属于类的方法。在类加载以后就可以自己调用,不需要创建任何类的是实例化对象。
例如下例代码中的方法是类的静态方法:
public class Text {
public static void main(String[] args) {
//Moo.add(3,4) 使用类名直接访问静态方法
System.out.println(Moo.add(3,4));
}
}
class Moo{
private int a=2;//对象属性
public Moo(){}
//静态方法属于类的方法,是公共的工具方法
//静态方法不能访问属于对象的属性
public static int add(int a,int b) {
//return a+b+this.a; //编译错误,使用方法时没有实例化对象
//this 和 static 不能一起用
return a+b;
}
}
(1) Java 的 String 就是 final 类,不能被继承
(2) Math 是 final 类,不能被继承
(3) Integer、Long、Character等包装类也是 final 类,不能被继承
(4) 在实际开发中,原则上不允许使用 final 类,因为 Sping、Hibernate等框架使用了“动态继承代理”技术,使用 final 类会影响实现
(1) final 类修饰方法,修饰的方法不能再被覆盖(继承中的方法重写)
(2) 在实际开发中,原则上不允许使用 final 类, 原因和上述一样
final 可以修饰变量,修饰的变量初始化后不允许再被修改
(1) final 可以修饰局部变量
(2) final 可以修饰方法参数
(3) final 可以修饰成员变量
(1) Java 使用 static final 修饰的变量作为常量
(2) 一般要求常量名都是大写字母
4)** 在实际开发中,原则上不允许使用 final 类,因为 Sping、Hibernate等框架使用了“动态继承代理”技术,使用 final 类会影响实现
(1) final 类修饰方法,修饰的方法不能再被覆盖(继承中的方法重写)
(2) 在实际开发中,原则上不允许使用 final 类, 原因和上述一样
final 可以修饰变量,修饰的变量初始化后不允许再被修改
(1) final 可以修饰局部变量
(2) final 可以修饰方法参数
(3) final 可以修饰成员变量
(1) Java 使用 static final 修饰的变量作为常量
(2) 一般要求常量名都是大写字母