栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java 面向对象 (2)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java 面向对象 (2)

方法详解

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 前缀指定访问被覆盖的实例变量
使用规则

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

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

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

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);
			      	
			  }
			 		   
	   }
}
  • 对于一个循环变量而言,只需要它在循环体内有效即可
  • 考虑使用成员变量的几种情况
    • 用于描述某个类的固有信息
      • 类相关
      • 例如人类的眼睛数目
    • 用于描述某个实例的固有信息
      • 实例相关
      • 例如人类的每个人的身高体重
    • 用于保存某个类或某个实例运行时的状态信息
      • 例如五子棋程序中的棋盘数组
    • 用于在某个类的多个方法之间进行共享
      • 例如把浮点数转换为人民币读法字符串的程序中
      • 数字的大写字符和单位字符
  • 即使是使用局部变量,也应该尽可能缩小其生存时间和作用域
    • 例如能使用代码块局部变量的地方,就坚决不要使用方法局部变量
隐藏与封装

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

理解封装

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

  • 一个类常常就是一个小的模块
  • 仅让这个模块公开必须让外界知道的内容(低耦合)
  • 而隐藏其他一切实现的细节(高内聚)
  • 且尽量避免一个模块直接访问和操作另一个模块的数据
访问控制符
当前类访问权限包访问权限子类访问权限公共访问权限
privatedefaultprotectedpublic
同一个类中OKOKOKOK
同一个包中OKOKOK
子类中OKOK
全局范围内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());
				
		}
}
  • 如果一个 Java 类的每个实例变量都使用 private 修饰
  • 并为每个实例变量提供public 修饰的 setter 和 getter 方法
    • 同时加入一些逻辑控制
    • 以限制对实例变量的不合理访问
  • 那么这个类就是一个符合 JavaBean 规范的类
  • JavaBean 总是一个封装良好的类
几个良好的建议

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

  • 类里的绝大部分成员变量都应该使用 private 修饰
  • 只有一些 static 修饰的、类似全局变量的类变量,才可能考虑使用 public 修饰
  • 用于辅助实现该类的其他方法的方法(工具方法),应该使用 private 修饰
  • 希望子类重写的方法,应该使用 protected 修饰
  • 希望暴露出来给其他类自由调用的方法应该使用 public 修饰,例如构造器
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/970406.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号