13-方法和封装的概念

方法和封装的概念

构造方法的基本概念------------------------------
class 类名{
   类名(形参列表){
       构造方法体; //若是普通方法,通常也叫做普通方法体,当然,他们两个都可以统一叫做方法体
    }
}
//如
class Person{
    Person(){ //Person类中的构造方法
        
    }
}
构造方法名与类名完全相同并且没有返回值类型,连void都不许有
默认构造方法:当一个类中没有定义任何构造方法时,编译器会自动添加一个无参空构造即无参数的构造方法
叫做默认/缺省构造方法,如:
Person(){};
若类中出现了构造方法,则编译器不再提供任何形式的构造方法
构造方法的好处可以在构造方法里进行自己成员变量的操作,但默认的构造方法就没有这样的操作
构造方法的作用:使用new关键字创建对象时会自动调用构造方法实现成员变量初始化工作
/*
  编程实现Personn类的定义
 */
 public class Personn{
	 String name; //用于描述姓名的成员变量
	 int age;     //用于描述年龄的成员变量
	 
	 //自定义构造方法
	 /*
	 Personn(){
		// System.out.println("我就是自定义的构造方法!");
		//name = "张飞";
		//age = 30;
	 }
	 */
	 Personn(String s,int i){
	      name = s;
		  age = i;
	 }
	 
	 void show(){
		 //每当打印成员变量的数值时,让年龄增长一岁
		 this.grow(); //this.前缀可以去掉
		 System.out.println("我是" + name + ",今年" + age + "岁了!");
	 }
	 //自定义成员方法实现年龄增长一岁的行为
	 void grow(){
		 age++;
	 }
	 //自定义成员方法实现年龄增长参数指定数值的行为
	 void grow(int i){
		 age += i;
	 }
	 //自定义成员方法实现Personn类型对象的获取并返回的行为
	 Personn getPersonn(){
		 //返回当前调用对象本身 Person  tp = new Person(); return tp;
		 return this;
	 }
	  public static void main(String[] args){
		  //声明一个Personn类型的引用指向Personn类型的对象
		  //当类中没有提供构造方法时,则下面调用默认构造方法,若类中提供构造方法后,则下面调用类中提供的版本
		  Personn p1 = new Personn("张飞",30); //无参调用无参构造方法,有参调用有参构造方法
		  //并打印特征
		  p1.show(); //null 0 张飞 30
		  Personn p2 = new Personn("关羽",40);
		  p2.show(); //关羽 35
		  //Personn p3 = new Personn(); //错误: 无法将类 Personn中的构造器 Personn应用到给定类型;
		  //因为有构造方法了,那么编译器就不会自动添加默认的无参构造方法,所以他调用构造方法调用不到,即报错
		  //p3.show(); 
		System.out.println("--------------------------------------------------------------------");
		  p2.grow(); 
		  p2.show();//关羽 36
		  p2.grow(2);
		  p2.show();//关羽 38
		 System.out.println("--------------------------------------------------------------------");
        //调用成员方法去获取对象
        Personn pp = p1.getPersonn();
		System.out.println("p1 = " + p1);
		System.out.println("pp = " + pp);
        pp.show(); 		
		  
	  }
	 
	 
 }
案例题目------------------------------
编程实现Pointt类的定义并向Pointt类添加构造方法
Pointt()默认创建原点对象
Pointt(int i,int j)根据参数创建点对象
/*
  编程实现Pointt类的定义
 */
 public class Pointt{
	 int x; //用于表述横坐标的成员变量
	 int y; //用于表述纵坐标的成员变量
	 
	 //自定义无参构造方法
	 Pointt(){
		 
	 }
	 //自定义有参构造方法
	 Pointt(int i,int j){
		 x = i;
		 y = j;
		 
	 }
	 //自定义成员方法实现特征的打印
	 void show(){
		 System.out.println("横坐标是:" + x + ",纵坐标是:" + y);
	 }
	 void up(){
		 y--;
	 }
	 void up(int dy){
		 y -= dy;
	 }
	  public static void main(String[] args){
		  
		  //使用无参方式构造对象并打印特征
		  Pointt p1 = new Pointt();
		  p1.show();
		  //使用有参方式构造对象并打印特征
		  Pointt p2 = new Pointt(3,5);
		  p2.show();
		System.out.println("--------------------------------------------------------------------");
		  p2.up();
		  p2.show(); //3 4
		  p2.up(2);
		  p2.show(); //3 2
	  }
	 
 }
重载的概念和体现形式------------------------------
若方法名称相同,参数列表不同,这样的方法之间构成重载关系(Overload)
方法重载的主要形式体现在:参数的个数不同,参数的类型不同,参数的顺序不同,与返回值类型和形参变量名无关
但建议返回值类型最好相同,因为若不同,那么我们就要处理返回值,而相同时,则不用非常麻烦的处理
判断方法能否构成重载的核心:调用方法时能否加以区分
练习题目------------------------------
编程实现Pointt类添加重载的成员方法
up()实现纵坐标减1的功能
up(int dy)实现纵坐标减去参数指定数值的功能
测试重载方法的调用规则
/*
  编程实现Pointt类的定义
 */
 public class Pointt{
	 int x; //用于表述横坐标的成员变量
	 int y; //用于表述纵坐标的成员变量
	 
	 //自定义无参构造方法
	 Pointt(){
		 
	 }
	 //自定义有参构造方法
	 Pointt(int i,int j){
		 x = i;
		 y = j;
		 
	 }
	 //自定义成员方法实现特征的打印
	 void show(){
		 System.out.println("横坐标是:" + x + ",纵坐标是:" + y);
	 }
	 void up(){
		 y--;
	 }
	 void up(int dy){
		 y -= dy;
	 }
	  public static void main(String[] args){
		  
		  //使用无参方式构造对象并打印特征
		  Pointt p1 = new Pointt();
		  p1.show();
		  //使用有参方式构造对象并打印特征
		  Pointt p2 = new Pointt(3,5);
		  p2.show();
		System.out.println("--------------------------------------------------------------------");
		  p2.up();
		  p2.show(); //3 4
		  p2.up(2);
		  p2.show(); //3 2
	  }
	 
 }
重载的实际意义------------------------------
方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种不同的版本,来实现各种不同的功能
如:java.io.PrintStream类中的println方法
就类似于我们打印变量时的操作,变量可以是很多类型,那个也是重载,如:System.out.println()
/*
  编程实现方法重载主要形式的测试
 */
 public class OverloadTest{
	 
	 //自定义成员方法
	 void show(){
	 System.out.println("show()");
	 }
	 
	 void show(int i){ //ok 体现在方法参数的个数不同
	 System.out.println("show(int)");
	 }
	 void show(int i,double d){ //ok 体现在方法参数的个数不同
	 System.out.println("show(int,double)");
	 }
	 void show(int i,int j){ //ok 体现在方法参数的类型不同
	 System.out.println("show(int,int)");
	 }
	 void show(double i,int j){ //ok 体现在方法参数的顺序不同
	 System.out.println("show(double,int)");
	 }
	 
	  
	 /*
	 void show(double a,int b){ //error(错误) 与参数的变量名无关
	 System.out.println("show(double,int)");
	 }
	 */
	 /*
	 int show(double a,int b){ //error(错误) 与返回值类型无关
	 System.out.println("show(double,int)");
	 }
	 */
	 //在上面两个无关中,若使用的话,会指向两个方法,即不知道调用两个方法的哪一个,就会报错误
	 //即必须要只剩下一个方法,那么就不会报错
	 
	 
	 public static void main(String[] args){
		 
		 //声明OverloadText类型的引用指向该类型的对象
		 OverloadTest ot = new OverloadTest();
		 //调用show方法();
		 ot.show();
		 ot.show(66);
		 ot.show(66,3.14);
		 ot.show(66,3);
		 ot.show(3.14,66);
		 //ot.show(3.14,66);
		 
		 
	 }
	 
 }
this的基本概念------------------------------
若在构造方法中出现了this关键字,则代表当前正在构造的对象
若成员方法中出现了this关键字,则代表当前正在调用的对象
this关键字本质上就是当前类类型的引用变量
//当方法里有
System.out.println("我是" + name + ",今年" + age + "岁了!");
//name和age隐含着this关键字,即this.name和this.age
//如Person this = p1; this.name = p1.name = 张飞
//Person this = p2; this.name = p2.name = 关羽
this关键字的工作原理------------------------------
在构造方法中和成员方法中访问成员变量时,编译器会加上this.的前缀
而this.相当于汉语中的"我的",当不同的对象调用同一个方法时,由于调用方法的对象不同导致this关键字不同
从而this.方式访问的结果也随之不同
this使用方式------------------------------
//如有以下代码
public class test{
    int i;
    String s;
    //就进原则 懒人原则 当成员变量名与形参变量名同名时,谁近一点,赋值的就是谁
    test(int i,String s){
        //i = i;  i都是形参变量名
        //s = s;  s都是形参变量名
        this.i = i; //这样就可以让左边的为成员变量了
        this.s = s; //这样的操作可以知道该形参变量名服务与那个成员变量
        //以后基本上都这样写
    }
}
当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则)
若希望使用成员变量,则需要在成员变量的前面加上this.前缀,明确要求该变量是成员变量(重中之重),虽然一般回默认加上this,但是也会操作就近原则后操作
this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以作为方法的返回值(重点)
在构造方法的第一行可以通过this()的方式来调用本类中的其他构造方法(了解)
至于为什么必须是第一行,因为若不为第一行的话,在前面就对类的一些东西进行操作,如成员变量
那么操作完后,再用这个this调用构造方法的话,就会重复操作,而使得你明确使用这个构造,而没有执行他的具体实现(这是主观的问题),即就规定了只能第一行(否则报错)
/*
  编程实现this关键字的使用
 */
 public class ThisTest {
	 
	 //自定义构造方法
	 ThisTest(){
		 //this代表当前正在构造的对象  //
		 System.out.println("构造方法中:this = " + this); 
	 }
	 //自定义成员方法
	 void show(){
		 //this代表当前正在调用的对象
		 System.out.println("成员方法中:this = " +this);
	 }
	 
	  public static void main(String[] args) {
		  
		  //声明ThisTest类型的引用指向该类型的对象
		  ThisTest tt = new ThisTest();
		  //调用show()方法
		  tt.show();
		  System.out.println("main方法中:tt = " + tt); 
		  
		  
	  }
	 
	 
	 
	 
 }
注意:this是在执行时,才会有的,即谁执行就代表谁,如a.fa(),就代表a,new aa()就代表他这个地址
/*
  编程实现Boy类的定义
 */
 public class Boy {
	 
	 String name; //用于描述姓名的成员变量
	 
	 //自定义构造方法
	 Boy(){
		 //调用本类中的有参构造方法
		 //this(); 错误: 递归构造器调用 不可重复调用本身(在idea检查时就会报错,即提示,而不用启动后才会报错,当然,检查时报错,在没有特别情况下,启动后也会报错的,除非是spring中的注入操作那里或者其他某些地方,检查虽然报错,但启动不会报错,以后学习spring或者相关操作时,特别是mp,就会知道的,比如77章博客中的"若出现爆红,不需要管,这是idea认为没有注入,而出现的爆红"这个地方,你可以全局搜索找到即可)
		 //this("张飞");
		 System.out.println("无参构造方法");
	 }
	 Boy(String name){
		 this(); //再使用构造方法时,若其中有调用了某个构造方法,那么调用的构造方法若能回来的话,就会报错
		 //如this()里面有this(1),this(1)里面有this()那么就会无限循环,即报错(一般idea的检查就会出现错误)
		 System.out.println("-------有参构造方法");
		 this.name = name;
	 }
	 //自定义成员方法实现特征的打印
	 void show(){
		 System.out.println("我的名字是:" + name);
	 }
	 public static void main(String[] args) {
		 
		 //使用无参方式构造对象并打印特征
		 Boy b1 = new Boy();
		 b1.show(); //null
		 
		 System.out.println("--------------------------------------------------------------------");
		 //使用有参方式构造对象并打印特征
		 Boy b2 = new Boy("张飞");
		 b2.show(); //张飞
		 
	 }
	 
	 
 }
 
注意事项------------------------------
引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象
当某个引用类型变量为null时,无法对对象实施访问(因为它没有指向任何对象)
此时,如果通过引用访问成员变量或调用方法,会产生NullPointerException异常
案例题目------------------------------
编程实现参数n的阶乘并返回,所谓阶乘就是从1累乘到n的结果
/*
  编程实现累乘积的计算并打印
 */
 public class JieChengTest{
	 //自定义成员方法实现将参数n的阶乘计算出来并返回
	 // 1! = 1; 2! = 2; 3! = 6; ... n! = 1*2*3*...*n;
	 int show(int n){ //int 5
		 //递推
		 /*
		 int num = 1;
		 for(int i = 1;i<=n;i++){
			 num *= i;
		 }
		 return num;
		 */
		 /*
		 5!= 5*4*3*2*1;
		 4! = 4*3*2*1;
		 3! = 3*2*1;
		 2! = 2*1;
		 1! = 1;
		 5! = 5 * 4!;
		 4! = 4 * 3!;
		 3! = 3 * 2!;
		 2! = 2 * 1!;
		 1! = 1;
		 n! = n * (n-1)!;
		 */
		 //递归的方式
		 //当n的数值为1时,则阶乘的结果是1
		 /*
		 if(1 == n){
			return 1; 
		 }
		 */
		 if(1 == n) return 1;
		 //否则阶乘的结果就是 n*(n-1)
		 return n * show(n-1);
		 //show(5) => return 5*show(4); =>120
		 //show(4) => return 4*show(3); =>24
		 //show(3) => return 3*show(2); =>6
		 //show(2) => return 2*show(1); =>2
		 //show(1) => return 1; => 1
		 
	 }
	 public static void main(String[] args) {
		 //声明JieChengTest类型的引用指向该类型的对象
		 JieChengTest jct = new JieChengTest();
		 //调用方法进行计算并打印
		 int res = jct.show(5);
		 System.out.println("最终的计算结果是:" + res);
		 
	 }
	 
 }
递归的基本概念------------------------------
递归本质就是指在方法体的内部直接或间接调用当前方法自身的形式
使用递归必须有递归的规律以及退出条件
使用递归必须使得问题简单化而不是复杂化
若递归影响到程序的执行性能,则使用递推或者递归(更好的)或者其他方式取代之

在这里插入图片描述

案例题目------------------------------
编程实现费式数列中第n项的数值并返回
费式数列:1 1 2 3 5 8 13 21 …
/*
  编程实现费式数列的计算并打印
 */
 public class FeeTest{
	 
	 //自定义成员方法实现费式数列中第n项数值的计算并返回,n由参数指定
	 // 1 1 2 3 5 8 13 21 ....
	 int show(int n){ // int n = 5
	     /*
		 //使用递归的方式进行计算
		 //当n=1或者n=2时,结果是1
		 if(1 == n || 2 == n){
			 return 1;
		 }
		 //否则结果是前两项的和
		 return show(n-1) + show(n-2);
		 //show(5) => return show(4) + show(3); =>5
		 //show(4) => return show(3) + show(2); =>3
		 //show(3) => return show(2) + show(1); =>2
		 //show(2) => return 1;                 =>1
		 //show(1) => return 1;                 =>1
		 */
		 //使用递推的方式进行计算
		 int ia = 1;
		 int ib = 1;
		 for(int i= 3; i<=n; i++){
			 int ic = ia + ib;
			 ia = ib;
			 ib = ic;
			 
		 }
		 return ib;
	 }
	 public static void main(String[] args) {
		 //声明FeeTest类型的引用指向该类型的对象
		 FeeTest ft = new FeeTest();
		 //调用方法计算并打印
		 int res = ft.show(5);
		 System.out.println("最终结果是:" + res); // 5
		 
	 }
	 
	 
 }
将上述代码拆分
/*
  编程实现费式数列的计算并打印 功能类
 */
 public class Fee{
	 
	 //自定义成员方法实现费式数列中第n项数值的计算并返回,n由参数指定
	 // 1 1 2 3 5 8 13 21 ....
	 int show(int n){ // int n = 5
	     /*
		 //使用递归的方式进行计算
		 //当n=1或者n=2时,结果是1
		 if(1 == n || 2 == n){
			 return 1;
		 }
		 //否则结果是前两项的和
		 return show(n-1) + show(n-2);
		 //show(5) => return show(4) + show(3); =>5
		 //show(4) => return show(3) + show(2); =>3
		 //show(3) => return show(2) + show(1); =>2
		 //show(2) => return 1;                 =>1
		 //show(1) => return 1;                 =>1
		 */
		 //使用递推的方式进行计算
		 int ia = 1;
		 int ib = 1;
		 for(int i= 3; i<=n; i++){
			 int ic = ia + ib;
			 ia = ib;
			 ib = ic;
			 
		 }
		 return ib;
	 }
	 
	 
	 
 }
/*
  编程实现费式数列类的测试  测试类
 */
 public class FeeTest{

	 public static void main(String[] args) {
		 //声明Fee类型的引用指向该类型的对象
		 Fee ft = new Fee();
		 //调用方法计算并打印
		 int res = ft.show(5);
		 System.out.println("最终结果是:" + res); // 5
		 
	 }
	 
	 
 }
 
上述可以分开调用,编译FeeTest类的同时main方法的Fee类也会编译,最后执行FeeTest类可以得到相应结果
但这里不可以直接用java FeeTest.java运行了,可以解释为因为他对该类操作时,编译的字节码文件放在某个地方
并执行该字节码文件,但若你的Fee类编译了,那么由于Fee类的字节码文件(认为不在一个地方)与FeeTest字节码文件不在同一地方(包,文件夹),在同一个地方的一般是可以的(一般来说,java FeeTest.java在一个类里面可以,分开通常不行,这里认为这样可能分主体,导致位置不同(字节码),但是一个地方的位置会相同的),可以自行测试,这里不用多说
就会报错,除非用的Fee类的东西是由Public修饰那么就不会报错(但他并不会,因为不是我们主动写的),实际上这样的操作可以理解成,只能允许某些操作
具体可以看看31章博客的最后的说明

在这里插入图片描述

从上述可知,递归需要执行很多次,会影响性能,即使用递推
封装的概念------------------------------
通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示
此时与现实生活不符
为了避免上述错误的发生,就需要对成员变量进行密封包装处理
来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装
封装的实现流程------------------------------
私有化成员变量,使用private关键字修饰
提供公有的get和set方法,并在方法体中进行合理值的判断
在构造方法中调用set方法进行合理值的判断
/*
  编程实现Student类的封装
 */
 public class Student{
    //私有化成员变量,使用private关键字修饰
	//private关键字修饰表示私有的含义,也就是该成员变量只能在当前类的内部使用
	private int id; //用于描述学号的成员变量
	private String name; //用于描述姓名的成员变量
	 
	 public Student(){
		 
	 }
	 //在公有的构造方法中调用set方法进行合理值的判断
	 public Student(int id,String name){
		 //this.id = id;
		 //this.name = name;
		 setId(id);
		 setName(name);
	 }
	 //提供公有的get和set方法,并在方法体中进行合理值的判断
	 //使用public关键字修饰表示公有的含义,也就是该方法可以在任意位置使用
	 public int getId(){
		 return id;
	 }
	 public void setId(int id){
		 if(id > 0){
		 this.id = id;
		 }else{
			 System.out.println(id + "学号不合理哦");
		 }
		 
	 }
	 public String getName(){
		 return name;
	 }
	 public void setName(String name){
		 this.name = name;
	 }
	 
	 //自定义成员方法实现特征的打印
	 //什么修饰符都没有叫做默认的访问权限,级别介于private和public之间
	 void show(){
		 //System.out.println("我是:" + name + ",我的学号是:" + id);
		 System.out.println("我是:" + getName() + ",我的学号是:" + getId()); //该方式可维护性更强
	 }
	 
 }
/*
  编程实现Student类的测试
 */
 public class StudentTest{

	public static void main(String[] args) {
		
		//声明Student类型的引用指向Student类型的对象
		Student s1 = new Student();
		//对成员变量进行赋值并打印
		//s1.id = 100;
		//s1.name = "张飞";
		s1.setId(100);
		s1.setName("张飞");
		s1.show();
		System.out.println("--------------------------------------------------------------------");
		//s1.id = -1100;
		//s1.name = "张飞";
		s1.setId(-1100);
		s1.setName("张飞");
		s1.show();
		System.out.println("--------------------------------------------------------------------");
		//使用有参方式构造对象并打印特征
		Student s2 = new Student(-1001,"关羽");
		s2.show();
		
	}
	 
	 
 }
案例题目------------------------------
提示用户输入班级的学生人数以继每个学生的信息,学生的信息有:学号,姓名,最后分别打印出来
提示:Student[] arr = new Student[num];
/*
    编程实现学生信息的录入和打印
 */

import java.util.Scanner; 
 
public class StudentTest2 {
	
	public static void main(String[] args) {
		
		// 1.提示用户输入学生的人数并使用变量记录
		System.out.println("请输入学生的人数:");
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();
		
		// 2.根据学生的人数准备对应的一维数组
		// int[] arr = new int[3];  - 表示声明一个长度为3元素类型为int类型的一维数组
		// 数组中的每个元素都是int类型,也就是说数组中的每个元素都可以看做是一个int类型的变量
		//使用整数数据进行初始化 arr[0] = 10;
		// 下面的代码是声明一个长度为num元素类型为Student类型的一维数组
		// 数组中的每个元素都是Student类型,也就是说数组中的每个元素都可以看做Student类型的变量
		//arr[0] = new Student();
		Student[] arr = new Student[num];
		
		
		// 3.提示用户输入每个学生的信息(学号 姓名)并记录到一维数组中
		for(int i = 0; i < num; i++) {
			System.out.println("请输入第" + (i+1) + "个学生的信息(学号 姓名):");
			arr[i] = new Student(sc.nextInt(), sc.next());
		}
		
		System.out.println("-----------------------------------------------");
		// 4.打印所有学生信息
		System.out.println("该班级的所有学生信息有:");
		for(int i = 0; i < num; i++) {
			//System.out.println(arr[i]);
			arr[i].show();
		}
	}
}
JavaBean的概念------------------------------
JavaBean是一种Java语言写成的可重用组件,其他Java类可以通过反射机制发现和操作这些JavaBean的属性
JavaBean本质上就是符合以下标准的Java类
类是公共的
有一个无参的公共的构造器
有属性,且有对应的get,set方法,也可以实现序列化(即Serializable,通常也会加上,防止以后出现问题,在41章博客就有说明)
总结------------------------------
构造方法(重中之重)
语法格式、默认构造方法、实现成员变量的初始化
方法重载(重点)
概念、体现形式、实际意义
this关键字(原理)
概念、原理、使用方式
递归(难点)
概念、使用原则
封装(重中之重)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值