所属性Java 语言是静态的,一个类定义完成后,只要不再重新编译这个类文件,该类和该类的对象所拥有的方法是固定的,永远都不会改变
方法只能在类体内定义
- 方法不能独立存在
- 逻辑上必须属于一个类或一个对象
- 方法不能独立执行
- 主调者必须是一个类或一个对象
形参个数可变的参数本质就是一个数组参数
public class HelloWorld
{
public static void A(String...poems)
{
for(String poem : poems)
{
System.out.println(poem);
}
}
public static void main(String[] args)
{
A("林花谢了春红" ,
"太匆匆" ,
"无奈朝来寒雨晚来风" );
}
}
public class HelloWorld
{
public static void A(String...poems)
{
for(String poem : poems)
{
System.out.println(poem);
}
}
public static void main(String[] args)
{
A(new String[]{"胭脂泪" ,
"相留醉" ,
"几时重" ,
"自是人生长恨水长东"});
}
}
- 个数可变的形参只能处于形参列表的最后
- 即一个方法中最多只能有一个个数可变的形参
- 如果声明为数组形参,则调用时必须传给形参一个数组,而不是多值传入
一个方法调用了它自身
public class HelloWorld
{
public static int f(int n)
{
if(n == 0)
{
return 1;
}
else if(n == 1)
{
return 4;
}
else
{
return 2 * f(n - 1) + f(n - 2);
}
}
public static void main(String[] args)
{
System.out.println(f(10));
}
}
public class HelloWorld
{
public static int f(int n)
{
if(n == 20)
{
return 1;
}
else if(n == 21)
{
return 4;
}
else
{
return f(n + 2) - 2 * f(n + 1);
}
}
public static void main(String[] args)
{
System.out.println(f(10));
}
}
- 一定要向着已知的方向递归
一个类里定义多个同名的方法
系统一糊涂,肯定就是你错了
public class HelloWorld
{
public void A()
{
System.out.println("帘外雨潺潺");
System.out.println("春意阑珊");
System.out.println("罗衾不耐五更寒");
}
public void A(String...s1)
{
for(String s : s1)
{
System.out.println(s);
}
}
public static void main(String[] args)
{
HelloWorld h = new HelloWorld();
h.A();
h.A("梦里不知身是客" , "一晌贪欢");
}
}
public class HelloWorld
{
public void A(String s1)
{
System.out.println(s1);
}
public void A(String...s2)
{
for(String s : s2)
{
System.out.println(s);
}
}
public static void main(String[] args)
{
HelloWorld h = new HelloWorld();
h.A("独自莫凭栏");
h.A();
h.A(new String[]{"无限江山"});
h.A("别时容易见时难" , "流水落花春去也" , "天上人间");
}
}
-
两同一不同:
- 同一个类
- 同一个方法名
- 不同的形参列表
-
系统根据传入的实参列表来决定调用那个方法
-
方法重载与方法的修饰符、返回值类型等没有任何关系
-
一般不推荐重载形参个数可变的方法,容易降低程序的可读性
成员变量变量的生存时间和作用域就像人的年龄,小时候很可爱,长大了很讨厌
类变量 + 实例变量
class A
{
public String s;
public static int a;
}
public class HelloWorld
{
public static void main(String[] args)
{
System.out.println(A.a);
A a1 = new A();
System.out.println(a1.a);
a1.s = "Hi~";
a1.a = 18;
System.out.println(a1.s);
System.out.println(a1.a);
System.out.println(A.a);
A a2 = new A();
System.out.println(a2.s);
System.out.println(a2.a);
}
}
- 类变量作为类本身的一个成员
- 从类的准备阶段起开始存在
- 直到系统完全销毁这个类
- 与类本身共存亡
- 实例变量作为实例的一个成员
- 从该实例被创建起开始存在
- 直到系统完全销毁这个实例
- 与实例共存亡
- 类变量的作用域 > 实例变量的作用域
- 成员变量无须显式初始化
- 系统会在类的准备阶段为类变量进行默认初始化
- 系统会在创建实例时为实例变量进行默认初始化
- 成员变量的默认初始化赋值规则 = 数组的默认初始化赋值规则
- 同一个类的所有实例对象访问&修改类变量时
- 实际上访问&修改的是该类本身的同一个变量
- 与通过类本身来访问&修改类变量的影响完全一样
- 也就是说,都访问&修改了同一片内存区
方法签名中的形参 + 方法局部变量 + 代码块局部变量
public class HelloWorld
{
public static void main(String[] args)
{
{
int a;
a = 5;
System.out.println(a); //代码块中有效,输出:5
}
System.out.println(a); //不可再访问,编译错误:找不到符号
}
}
- 形参
- 整个方法内有效
- 无须显式指定初始值,在调用方法时由主调者负责指定
- 当通过类或对象调用某个方法时
- 系统会在该方法的栈区内为所有的形参分配内存空间
- 方法局部变量
- 从声明定义处开始生效
- 必须显式指定初始值,否则不可访问
- 因为此时系统还没有分配内存空间给方法局部变量
- 直到为方法局部变量赋值时
- 系统才会为它们分配可访问的内存空间(方法所在的栈区内)
- 到方法结束时失效
- 代码块局部变量
- 从声明定义处开始生效
- 必须显式指定初始值,否则不可访问
- 因为此时系统还没有分配内存空间给代码块局部变量
- 直到为代码块局部变量赋值时
- 系统才会为它们分配可访问的内存空间(方法所在的栈区内)
- 到代码块结束时失效
大部分时候还是应该尽量避免同名现象
public class HelloWorld
{
public static void main(String[] args)
{
{
int i = 0;
System.out.println(i);
}
{
int i = 18;
System.out.println(i);
}
int i = 999;
System.out.println(i);
{
int i = 1;
System.out.println(i); //编译错误:已在方法 main(String[]) 中定义了变量 i
}
}
}
public class HelloWorld
{
private String s = "H";
private static int i = 18;
public void A()
{
String s = "h";
System.out.println(s);
System.out.println(this.s);
int i = 1;
System.out.println(i);
System.out.println(HelloWorld.i);
}
public static void main(String[] args)
{
new HelloWorld().A();
String s = "hh";
System.out.println(s);
System.out.println(new HelloWorld().s);
int i = 2;
System.out.println(i);
System.out.println(HelloWorld.i);
}
}
- 同一个类里不能定义两个同名的成员变量,即使一个是类变量,一个是实例变量
- 同一个方法中形参不能与方法局部变量同名
- 同一个方法中方法局部变量不能同名
- 同一个方法中不同的代码块局部变量可以同名
- 同一个方法中如果先定义代码块局部变量,后可定义一个同名的方法局部变量
- Java 允许成员变量和局部变量同名
- 不过局部变量会覆盖成员变量
- 需要显式使用类名作为调用者指定访问被覆盖的类变量
- 需要显式使用 this 前缀指定访问被覆盖的实例变量
定义一个成员变量时,成员变量将被放置到堆内存中:
- 增大了变量的生存时间,将导致更大的内存开销
- 扩大了变量的作用域,不利于提高程序的内聚性
局部变量不属于任何类或实例,它总是被保存在其所在方法的栈内存中
public class HelloWorld
{
static int i; //定义一个类变量
public static void main(String[] args)
{
for (i = 0 ; i < 3 ; i++)
{
System.out.println(i);
}
}
}
public class HelloWorld
{
public static void main(String[] args)
{
int i; //定义一个方法局部变量
for (i = 0 ; i < 3 ; i++)
{
System.out.println(i);
}
}
}
public class HelloWorld
{
public static void main(String[] args)
{
for (int i = 0 ; i < 3 ; i++) //定义一个代码块局部变量
{
System.out.println(i);
}
}
}
- 对于一个循环变量而言,只需要它在循环体内有效即可
- 考虑使用成员变量的几种情况
- 用于描述某个类的固有信息
- 类相关
- 例如人类的眼睛数目
- 用于描述某个实例的固有信息
- 实例相关
- 例如人类的每个人的身高体重
- 用于保存某个类或某个实例运行时的状态信息
- 例如五子棋程序中的棋盘数组
- 用于在某个类的多个方法之间进行共享
- 例如把浮点数转换为人民币读法字符串的程序中
- 数字的大写字符和单位字符
- 用于描述某个类的固有信息
- 即使是使用局部变量,也应该尽可能缩小其生存时间和作用域
- 例如能使用代码块局部变量的地方,就坚决不要使用方法局部变量
理解封装太多的秘密和太少的秘密都说明了精神的软弱
把该隐藏的隐藏起来,把该暴露的暴露出来
- 一个类常常就是一个小的模块
- 仅让这个模块公开必须让外界知道的内容(低耦合)
- 而隐藏其他一切实现的细节(高内聚)
- 且尽量避免一个模块直接访问和操作另一个模块的数据
| 当前类访问权限 | 包访问权限 | 子类访问权限 | 公共访问权限 | |
|---|---|---|---|---|
| private | default | protected | public | |
| 同一个类中 | OK | OK | OK | OK |
| 同一个包中 | OK | OK | OK | |
| 子类中 | OK | OK | ||
| 全局范围内 | OK |
- 对于外部类而言,只能使用 public 和 default 访问控制符
- 外部类没有其所在类的内部、所在类的子类两个范围
- 因此 private 、default 对外部类没有任何意义
- 对于类的成员变量、方法、构造器而言,可以使用任何一种访问控制符
- 对于局部变量而言,其作用域就是它所在的方法,不能使用访问控制符
class A
{
private String name;
private int age;
public void setName(String name) //void public 修饰的 setter
{
if(name.length() > 6 || name.length() < 2)
{
System.out.println("您设置的人名不符合要求");
return;
}
else
{
this.name = name;
}
}
public String getName() //String public 修饰的 getter
{
return this.name;
}
public void setAge(int age) //void public 修饰的 setter
{
if(age > 100 || age < 0)
{
System.out.println("您设置的额年龄不符合要求");
return;
}
else
{
this.age = age;
}
}
public int getAge() //int public 修饰的 getter
{
return this.age;
}
}
public class HelloWorld
{
public static void main(String[] args)
{
A a = new A();
a.setAge(117);
System.out.println(a.getAge());
a.setName("士官长");
System.out.println(a.getName());
}
}
- 如果一个 Java 类的每个实例变量都使用 private 修饰
- 并为每个实例变量提供public 修饰的 setter 和 getter 方法
- 同时加入一些逻辑控制
- 以限制对实例变量的不合理访问
- 那么这个类就是一个符合 JavaBean 规范的类
- JavaBean 总是一个封装良好的类
建议从来就不是给自己准备的
- 类里的绝大部分成员变量都应该使用 private 修饰
- 只有一些 static 修饰的、类似全局变量的类变量,才可能考虑使用 public 修饰
- 用于辅助实现该类的其他方法的方法(工具方法),应该使用 private 修饰
- 希望子类重写的方法,应该使用 protected 修饰
- 希望暴露出来给其他类自由调用的方法应该使用 public 修饰,例如构造器



