方法详解


Java 语言是静态的,一个类定义完成后,只要不再重新编译这个类文件,该类和该类的对象所拥有的方法是固定的,永远都不会改变

所属性

方法只能在类体内定义

  • 方法不能独立存在

    • 逻辑上必须属于一个类或一个对象
  • 方法不能独立执行
    • 主调者必须是一个类或一个对象

形参个数可变

形参个数可变的参数本质就是一个数组参数

public class HelloWorld
{public static void A(String...poems)      /*可接受多个字符串参数多个字符串参数被当作数组传入*/{for(String poem : poems){System.out.println(poem);}/*foreach 循环遍历数组元素*/} public static void main(String[] args){     A("林花谢了春红" , "太匆匆"  ,"无奈朝来寒雨晚来风" );/*静态方法 main 访问静态方法 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[]{"胭脂泪" , "相留醉" , "几时重" , "自是人生长恨水长东"});/*静态方法 main 访问静态方法 A() 传入数组输出:胭脂泪相留醉几时重自是人生长恨水长东*/}
}
  • 个数可变的形参只能处于形参列表的最后
  • 即一个方法中最多只能有一个个数可变的形参
  • 如果声明为数组形参,则调用时必须传给形参一个数组,而不是多值传入

递归

一个方法调用了它自身

/*
已知 f(0) = 1
已知 f(1) = 4
已知 f(n + 2) = 2 * f(n + 1) + f(n)
试求 f(10)
递归调用形式;
return f(n) = 2 * f(n - 1) + f(n - 2);
*/
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);}/*向着已知的 f(0)=1 、 f(1)=4 方向递归*/}public static void main(String[] args){     System.out.println(f(10));/*输出:10497*/}
}/*
已知 f(20) = 1
已知 f(21) = 4
已知 f(n + 2) = 2 * f(n + 1) + f(n)
试求 f(10)
递归调用形式;
return f(n) = f(n + 2) - 2 * f(n + 1);
*/
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);}/*向着已知的 f(20)=1 、 f(21)=4 方向递归*/}public static void main(String[] args){    System.out.println(f(10));/*输出:-3771*/}
}
  • 一定要向着已知的方向递归

重载

一个类里定义多个同名的方法

系统一糊涂,肯定就是你错了

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("别时容易见时难" , "流水落花春去也" , "天上人间");/*调用 A(String s1) 一次调用 A(String...s2) 三次仅传入一个字符串参数将默认调用 A(String s1)想仅传入一个字符串参数且调用 A(String...s2) 需使用数组输出:独自莫凭栏无限江山别时容易见时难流水落花春去也天上人间*/    }
}
  • 两同一不同:

    • 同一个类
    • 同一个方法名
    • 不同的形参列表
  • 系统根据传入的实参列表来决定调用那个方法

  • 方法重载与方法的修饰符、返回值类型等没有任何关系

  • 一般不推荐重载形参个数可变的方法,容易降低程序的可读性

变量的选择


变量的生存时间和作用域就像人的年龄,小时候很可爱,长大了很讨厌

成员变量

类变量 + 实例变量

class A
{public String s;public static int a;
}public class HelloWorld
{public static void main(String[] args){      System.out.println(A.a);/*第一次主动使用类 A 类 A 自动初始化类变量 a 开始存在输出:0*/A a1 = new A();System.out.println(a1.a);/*实例 a1 被创建实例 a1 的实例变量 s 开始存在通过实例 a1 访问类变量 a输出:0*/a1.s = "Hi~";a1.a = 18;System.out.println(a1.s);System.out.println(a1.a);System.out.println(A.a);/*通过实例 a1 访问实例变量 s 并赋值通过实例 a1 访问类变量 a 并赋值输出:Hi~1818*/A a2 = new A();System.out.println(a2.s);System.out.println(a2.a);/*实例 a2 被创建实例 a2 的实例变量 s 开始存在通过实例 a2 访问类变量 a输出:null18*/}
}
  • 类变量作为类本身的一个成员

    • 从类的准备阶段起开始存在
    • 直到系统完全销毁这个类
    • 与类本身共存亡
  • 实例变量作为实例的一个成员
    • 从该实例被创建起开始存在
    • 直到系统完全销毁这个实例
    • 与实例共存亡
  • 类变量的作用域 > 实例变量的作用域
  • 成员变量无须显式初始化
    • 系统会在类的准备阶段为类变量进行默认初始化
    • 系统会在创建实例时为实例变量进行默认初始化
    • 成员变量的默认初始化赋值规则 = 数组的默认初始化赋值规则
  • 同一个类的所有实例对象访问&修改类变量时
    • 实际上访问&修改的是该类本身的同一个变量
    • 与通过类本身来访问&修改类变量的影响完全一样
    • 也就是说,都访问&修改了同一片内存区

局部变量

方法签名中的形参 + 方法局部变量 + 代码块局部变量

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}/*所有与方法局部变量同名的代码块局部变量必须全部在方法局部变量之前定义输出:018999*/             }
}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);/*方法局部变量 s 覆盖实例变量 s需要显式使用 this 前缀指定访问方法局部变量 i 覆盖类变量 i需要显式使用 HelloWorld 类名指定访问*/}public static void main(String[] args){    new HelloWorld().A();/*输出:hH118*/  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); /*方法局部变量 s 覆盖实例变量 s需要显式使用 this 前缀指定访问方法局部变量 i 覆盖类变量 i需要显式使用 HelloWorld 类名指定访问输出:hhH218*/}
}
  • 同一个类里不能定义两个同名的成员变量,即使一个是类变量,一个是实例变量
  • 同一个方法中形参不能与方法局部变量同名
  • 同一个方法中方法局部变量不能同名
  • 同一个方法中不同的代码块局部变量可以同名
  • 同一个方法中如果先定义代码块局部变量,可定义一个同名的方法局部变量
  • Java 允许成员变量和局部变量同名
    • 不过局部变量会覆盖成员变量
    • 需要显式使用类名作为调用者指定访问被覆盖的类变量
    • 需要显式使用 this 前缀指定访问被覆盖的实例变量

使用规则

定义一个成员变量时,成员变量将被放置到堆内存中:

  1. 增大了变量的生存时间,将导致更大的内存开销
  2. 扩大了变量的作用域,不利于提高程序的内聚性

局部变量不属于任何类或实例,它总是被保存在其所在方法的栈内存

public class HelloWorld
{static int i;                         //定义一个类变量public static void main(String[] args){   for (i = 0 ; i < 3 ; i++){System.out.println(i);/*输出:012*/   }}
}public class HelloWorld
{public static void main(String[] args){      int i;                         //定义一个方法局部变量for (i = 0 ; i < 3 ; i++){System.out.println(i);/*输出:012*/    }}
}public class HelloWorld
{public static void main(String[] args){      for (int i = 0 ; i < 3 ; i++)    //定义一个代码块局部变量{System.out.println(i);/*输出:012*/  }}
}
  • 对于一个循环变量而言,只需要它在循环体内有效即可
  • 考虑使用成员变量的几种情况
    • 用于描述某个类的固有信息

      • 类相关
      • 例如人类的眼睛数目
    • 用于描述某个实例的固有信息
      • 实例相关
      • 例如人类的每个人的身高体重
    • 用于保存某个类或某个实例运行时的状态信息
      • 例如五子棋程序中的棋盘数组
    • 用于在某个类的多个方法之间进行共享
      • 例如把浮点数转换为人民币读法字符串的程序中
      • 数字的大写字符和单位字符
  • 即使是使用局部变量,也应该尽可能缩小其生存时间和作用域
    • 例如能使用代码块局部变量的地方,就坚决不要使用方法局部变量

隐藏与封装


太多的秘密和太少的秘密都说明了精神的软弱

理解封装

把该隐藏的隐藏起来,把该暴露的暴露出来

  • 一个类常常就是一个小的模块
  • 仅让这个模块公开必须让外界知道的内容(低耦合)
  • 而隐藏其他一切实现的细节(高内聚)
  • 且尽量避免一个模块直接访问和操作另一个模块的数据

访问控制符

当前类访问权限 包访问权限 子类访问权限 公共访问权限
private default protected public
同一个类中 OK OK OK OK
同一个包中 OK OK OK
子类中 OK OK
全局范围内 OK
  • 对于外部类而言,只能使用 public 和 default 访问控制符

    • 外部类没有其所在类的内部、所在类的子类两个范围
    • 因此 private 、default 对外部类没有任何意义
  • 对于类的成员变量、方法、构造器而言,可以使用任何一种访问控制符
  • 对于局部变量而言,其作用域就是它所在的方法,不能使用访问控制符

setter 和 getter

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());/*输出:您设置的年龄不符合要求0士官长*/}
}
  • 如果一个 Java 类的每个实例变量都使用 private 修饰
  • 并为每个实例变量提供public 修饰的 setter 和 getter 方法
    • 同时加入一些逻辑控制
    • 以限制对实例变量的不合理访问
  • 那么这个类就是一个符合 JavaBean 规范的类
  • JavaBean 总是一个封装良好的类

几个良好的建议

建议从来就不是给自己准备的

  • 类里的绝大部分成员变量都应该使用 private 修饰
  • 只有一些 static 修饰的、类似全局变量的类变量,才可能考虑使用 public 修饰
  • 用于辅助实现该类的其他方法的方法(工具方法),应该使用 private 修饰
  • 希望子类重写的方法,应该使用 protected 修饰
  • 希望暴露出来给其他类自由调用的方法应该使用 public 修饰,例如构造器

java 面向对象 (2)相关推荐

  1. java面向对象-------静态初始化块

    1.构造方法用于对象的初始化!静态初始化块,用于类的初始化操作,在静态初始化块中不能直接访问非static成员. package java面向对象; /** * 测试静态初始化块 */public c ...

  2. JAVA面向对象-----final关键字

    JAVA面向对象-–final关键字 1:定义静态方法求圆的面积 2:定义静态方法求圆的周长 3:发现方法中有重复的代码,就是PI,圆周率.1:如果需要提高计算精度,就需要修改每个方法中圆周率. 4: ...

  3. Java学习笔记二十五:Java面向对象的三大特性之多态

    Java面向对象的三大特性之多态 一:什么是多态: 多态是同一个行为具有多个不同表现形式或形态的能力. 多态就是同一个接口,使用不同的实例而执行不同操作. 多态性是对象多种表现形式的体现. 现实中,比 ...

  4. 12 Java面向对象之多态

    JavaSE 基础之十二 12 Java面向对象之多态 ① 多态的概念及分类 多态的概念:对象的多种表现形式和能力 多态的分类 1. 静态多态:在编译期间,程序就能决定调用哪个方法.方法的重载就表现出 ...

  5. 猫抓老鼠-Java面向对象特点梳理

    我们先设计一个猫抓老鼠的小游戏: ⊙猫和老鼠都有名字和体重两种属性,猫有抓老鼠的方法,对应的老鼠则有逃跑的方法. ⊙首先游戏的结果是猫抓住了老鼠或者老鼠逃跑了,对于这两种情况,我们用体重来区分,若猫的 ...

  6. java面向对象特征及阐述,Java面向对象四个特征

    Java面向对象有四个特征:抽象.封装.继承.多态.其中封装.继承.多态又被称为Java的基本特征. 抽象: Java中会把客观事物抽象成一个类.类就是封装了数据以及操作这些数据的代码逻辑实体.用字符 ...

  7. 20155328 《Java程序设计》 实验二(Java面向对象程序设计) 实验报告

    20155328 <Java程序设计> 实验二(Java面向对象程序设计) 实验报告 单元测试 一.单元测试和TDD 编程时需理清思路,将编程需求等想好,再开始编.此部分可用伪代码实现. ...

  8. 第7篇-JAVA面向对象Ⅲ

    第7篇-JAVA面向对象Ⅲ 每篇一句 :任何值得去的地方,都没有捷径 初学心得: 温故而知新 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-04-09| JAVA面向对象 Ⅲ] 1.J ...

  9. 谈谈java面向对象之抽象,手把手带你搞定java面试之面向对象

    计算机语言晦涩难懂,打算利用通俗易懂的文字带领大家学习java基础.如果文中有什么错误的地方,欢迎大家在评论区指正,免得我误人子弟. Question:当面试JAVA开发岗位的时候,面试官最爱问的问题 ...

  10. java面向对象程序设计第三版_JAVA面向对象程序设计之创建型设计模式

    [本文详细介绍了JAVA面向对象程序设计中的创建型设计模式,欢迎读者朋友们阅读.转发和收藏!] 1 基本概念 1.1 什么是设计模式 设计模式( Design pattern )是一套被反复使用.多数 ...

最新文章

  1. dotnet 是 前30个增长最快速度的开源项目中排名第一的开发平台
  2. 《零基础》MySQL 安装(二)
  3. LQR 离散与连续问题
  4. phpexcel常见问题的解决办法
  5. 使用tc对linux中某ip段限速
  6. MacOS Big Sur 11.4 (20F71) OC 0.7.0 / Cl 5135 / PE 三分区原版黑苹果镜像
  7. linux视频补帧,SVP补帧软件最新版-SVP补帧软件免费版-QQ下载站
  8. 【前端】HTML5+CSS3 HTML基本特性(一)
  9. linux查看更多历史记录,查看更多历史,如何查看浏览历史记录
  10. 每日刷题:lightoj-1004 - Monkey Banana Problem
  11. Linux入门学习(六)—— 怎么更改文件的所有者、所属组?以及怎么更改系统创建的默认权限?
  12. poisoned dagger
  13. SAP ABAP开发个别概念理论区分理解
  14. 圆为什么规定一定是360度_圆为什么是360度?不一样的趣味知识,让你痴迷数学...
  15. 熟男,好男,傻男,超男?-------…
  16. php 实现店铺装修6
  17. MySQL系统库之mysql
  18. 猫叔产品读记 | 爆款车厘子、重做消费品、旅游大数据(1期)
  19. 零基础如何开始学编程
  20. 使用 J-LINK 解锁芯片

热门文章

  1. Naive UI 之modal
  2. 简单的一键部署LNMP架构shell脚本
  3. keepass2android插件,Keepass2Android
  4. Python处理超强反爬(TSec防火墙+CSS图片背景偏移定位)
  5. QPSK和16QAM基带信号解调误比特率理论限和仿真对比
  6. 丰富多彩的开放课程资源
  7. 交响乐排布及乐器音色特点
  8. 计算机世界报约稿,#约稿# 柯洁不行?中国计算机围棋科学家组团挑战AlphaGo...
  9. JDBC 中 CreateStatement 和 PrepareStatement 的区别
  10. 银号理财猛推期缴分成险 吉星高照名列力点