Java学习 11.15

Java 第三天 类和对象

1.1 对象

我们编程时候 要有 间接 的思想。为了达到间接 所有就有了 变量的概念。
   
在java中也有变量, 数据类型 变量名字 = 初始值;
变量只能存储一个数据,并且多个变量之间没有联系。例如  int a= 180;int b=190;int c= 80;int d = 90;
此时代表的是两个人的身高和体重,此时就很难区分哪个是一组。
   
所以就有了数组,java中也是有数组的。但是数组是通过索引值操作数据 arr[0] 我们从代码中 仅仅能知道获取数组中索引为0的数据。
但是索引为0的数据代表什么含义我们是不知道的。
   
所以就需要一个能存储多个数据 并且有语义话的数据类型来存储数据 -------  对象类型。
   
js中我们学过了对象
   
var  obj = {name:"张三",age:18};

java中也是有对象的,所以我们今天的学习 就是学习 java中的对象如何创建 如何存取数据。

1.2 类


java中要想创建对象 就必须有类。因为类是对象的模板 对象是类的实例。
   
其实就是说  java对象要想创建 首先得有一个类 才能创建该类的对象。

1.3 对象数据的存取


张三   18  北京   一年级                        兰博基尼   600   95号    大众                毛毛  5000   18   金毛
李四   20  南京   三年级                        法拉利     550   98号    大众                二哈  8000   15   哈士奇
王五   19  东京   二年级                                                                   旺财  300    5    田园

所以我们需要使用能存储一组数据并且有语义化的对象来存储。要用对象存储就必须现有类
   
A 创建一个类 (idea工具 创建Xxxx.java源文件的时候 会自动帮我们生成同名的公共类)  Student

package com.aaa.day02.test;
public class Student {}

B 添加成员变量 (在类中声明的变量 称之为 成员变量 在函数中声明的变量 叫做局部变量)
 添加哪些成员变量什么数据类型取决于要存储的数据  
   
package com.aaa.day02.test;
public class Student {

   String   name;
   int      age;
   String   address;
   String   grade;

}

C 创建对象并且存储数据(java中能主动调用的函数是main函数 所以我们从今天开始 测试和代码分开)
 没有对象怎么办  new一个    
public class JavaTest {

   public static void main(String[] args) {

       /* new Student()创建一个学生对象并且将其赋值给 Student s1引用 */
       Student  s1 = new Student();

       s1.name = "张三";
       s1.age = 19;
       s1.address = "北京";
       s1.grade = "一年级";

       Student  s2 = new Student();

       s2.name = "李四";
       s2.age = 20;
       s2.address = "南京";
       s2.grade = "三年级";

  }

}    
   
   

遇到的错误 : 1 忘写main函数 2 main写错了 3 命名不规范

1.4 类中的函数(方法)


控制代码块的执行。
   
if(){}   控制代码块是否执行
for(){}  控制代码块执行多少次
   
函数     控制代码块何时执行,调用的时候才会执行

java中的代码写到类中(classbody)。其实是函数体 (method body)

1.5 函数的作用


java中的类 有两个功能: A 添加成员变量 new 对象存储数据    B 添加函数 用来执行某些功能代码

 

面向过程思想:  只考虑功能的实现 没有考虑到后期的优化和维护
面向对象思想:  开发的时候不仅要实现功能 还要考虑到后期的优化和维护(所以面向对象开发的时候更麻烦了 后期改起来方便)

java中如何定义函数 如何调用函数 至于函数里面该写什么功能代码 都是后面我们需要练习的

1.6 函数的声明


声明的格式
修饰符   返回值类型   函数名字(参数列表){}
修饰符 public 公共的 还有其他的修饰符 之后会讲
返回值类型:
函数名字: 要见名知意,英文,小驼峰
        ===  包名 反域名全小写com.alibaba.taobao.test   类名 英文大驼峰  StudentController
        ===  变量名(局部变量 成员变量 静态变量)函数名 参数名 小驼峰  maxAge
        ===  final常量  全大写下划线
   
()   : 参数列表  注意 参数和返回值都是数据传递的方式 只不过传递的方向不一样    如果不需要传递数据则 返回值类型写void 参数小括号什么都不写
{}    函数的代码块 method body
   
public class Haha {
   /**
   * 无参数 无返回值的函数
   */
   public void   hehe(){

       System.out.println("你好 世界");
       System.out.println("你好 世界");
       System.out.println("你好 世界");
       System.out.println("你好 世界");

  }
    public void heihei(){
       System.out.println("你好 中国 ");
  }
}

1.7 函数的调用


注意:我们现在讲的都是非static的函数
public class JavaTest3 {
   public static void main(String[] args) {

        Haha   h1 =   new Haha();
        // 对象名.函数名();
        h1.hehe();
        h1.heihei();
  }
}

1.8函数中的参数


参数是我们从来传递数据的一种方式
(java中的类不可以重名  因为java检查的是类的全限定名  com.aaa.day02.test.Haha   com.aaa.day02.test1.Haha  
例如

public class Haha {
   public  void eat(){
       System.out.println("就是爱吃饭");
  }
}

public class JavaTest {
   public static void main(String[] args) {
       String  str = "毛血旺";
       Haha   h1 = new  Haha();
       h1.eat();
  }
}
需求就是 main函数的 毛血旺 传递给 eat函数里面 (我们这个地方提出来的需求 就是演示一下数据传递的方式)

此时我们要思考一下 :    
   此时是调用方 需要将数据传递给 执行方  此时使用 参数的形式


A 在执行方 函数中添加参数 (传递几个数据 什么数据类型)
public class Haha {

   public  void eat(String   a){

       System.out.println("就是爱吃饭:" +  a);

  }

}
B 在调用方 调用函数时 需要给参数传递数据
public static void main(String[] args) {

       String  str = "毛血旺";
       Haha   h1 = new  Haha();
       h1.eat(  str   );

}

注意: java是一门强语言,要求 参数传递的时候 个数类型等 都需要匹配
  eat(String) in Haha cannot be applied to (int)
  eat(String) in Haha cannot be applied to (String,String)
   
练习:A   请实现两个数求和的函数      B 请实现一个数求立方的函数  C 请实现获取身高体重 告知偏胖偏偏瘦标准 函数    
public class Haha {

   public  void eat(String   a){
       System.out.println("就是爱吃饭:" +  a);
  }

   public void sum(int   a ,int b ){
       int  c = a+b;
       System.out.println(c);
  }

   public void cube(int  a){
       int  r = a*a*a;
       System.out.println(r);
  }

   public void check(double height,double  weight){

       double  b = height-105;
       double min = b-5;
       double max = b+5;

       if(weight > max){
           System.out.println("超重");
      }else if(weight < min){
           System.out.println("多吃点");
      }else{
           System.out.println("继续保持");
      }
  }
}    

public class JavaTest {
   public static void main(String[] args) {

       String  str = "毛血旺";
       Haha   h1 = new  Haha();
       h1.eat(  str );

       h1.sum(20,30);
       h1.sum(60,80);

       h1.cube(10);

       h1.check(180,80);
       h1.check(175,80);

  }
}  

1.9 函数中的返回值


返回值 又有一个好听的名字 叫做 回传参
他也是数据传递的一种方式,是由执行方传递数据给调用方

 


A  返回值类型写具体的类型 (你想回传什么类型的数据 返回值类型就写什么类型 如果没有返回值则写 void)
public class Haha {
   public int foo(){
       int  a = 30;
       return  a;
  }
}

B 在调用方调用函数的时候 可以通过赋值的形式 获取函数的返回值
public class JavaTest {
   public static void main(String[] args) {
        Haha a = new  Haha();
        /*首先调用 foo函数 并且在函数执行完成之后 将返回值赋值给了 b */
        int  b = a.foo();
        System.out.println(b);
  }
}

1.10 函数中的返回值语法规则(b)

1 不需要返回值 则写void
2 需要返回值则 写具体的数据类型
3 有返回值的函数 需要有一个可执行的return语句
  public String foo(){ }
  public String foo(){
       int  a = 20;
       if(a>10){
           return  "毛血旺";
      }
  }
  Missing return statement
     
4 return的数据要和返回值类型匹配
5 return语句执行之后 函数体结束 后面的代码就不执行了    
   public String foo(){
       return  "123123";
       /*Unreachable statement*/
       System.out.println("你好 世界级");
  }
6 void类型不能写 (return 但是可以有return    
  /**
    * Cannot return a value from a method with void result type
    */
   public void foo(){
       return  "123123";
  }  
   此时的return 仅仅代表结束函数体的意思  类似于break
   public void foo(){
       System.out.println("123123");
       return;  
  }
7有返回值的函数  在调用的时候可以将返回值 赋值给同类型的变量  
 Haha a = new  Haha();
 int  b =  a.foo();
 System.out.println(b);  
   

1.11 构造函数(constructor)


我们创建对象的时候 写的代码是
   
Haha  h1 = new  Haha();

其中Haha() 就是Haha类的构造函数
   
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。

1.12 构造函数的特征(b)


A 一个类如果不写 编译之后会自动生成一个公共无参数的构造函数
B 如果写要按照这样的格式
 普通函数:                                    构造函数:      
 修饰符  返回值类型  函数名(){                   修饰符  类名(){
   
}                                           }
 public class Haha {
   public Haha(){
       System.out.println("你好是和解");
  }
}
C 构造函数不写返回值类型 也不能写  
public class Haha {
   public void Haha(){
       System.out.println("你好是和解");
  }
}
Method name 'Haha' is the same as its class name
Inspection info: Reports methods being named identically to their class. A method with such a name may be easily mistaken for a constructor.
我们添加了返回值类型 此时不会报错 会报警告,因为语法上来讲没毛病 但是此时就不是构造函数le 而是一个普通函数 ,那么普通函数的名字和构造函数逇名字一样 不合适。
   
D 构造函数的名字要和类名相同
public class Haha {

   public  haha(){
       System.out.println("你好是和解");
  }

}
Invalid method declaration; return type required
此时名字是小写的haha 和类名不一样 所以就将其当成一个普通函数。普通函数必须写返回值类型    

E 如果写了有参数的构造函数 那么公共无参数的构造函数就不会自动生成了
     

1.13 构造函数的应用


构造函数的应用有很多
例如:A 为对象成员变量赋初始值  B 初始化内部数据 ...

类的作用是创建对象存数据
   
public class People {

   int   id;
   String  name;
   String  address;
   int   age;

}
public class JavaTest {

   public static void main(String[] args) {

       People   p1 =   new  People();

       p1.id = 666;
       p1.name = "zhangsna ";
       p1.age = 18;
       p1.address = "北京";

       People  p2 = new  People();

       p2.id = 777;
       p2.name = "李四";
       p2.age = 19;
       p2.address = "南京";

  }
}
我们这样操作能行,但是不优秀 所以要优化这段代码。核心思想就是干掉重复代码
我们可以使用有参数的构造函数进行代码的优化    

public class People {

   int   id;
   String  name;
   String  address;
   int   age;

   public People(int  a,String  b,String  c ,int d){
       id = a;
       name = b;
       address = c;
       age = d;
  }

}  
public class JavaTest {

   public static void main(String[] args) {

       People   p1 =   new  People(666,"张三","北京",18);
       People   p2 =   new  People(777,"李四","南京",20);


       System.out.println(p1.id);
       System.out.println(p2.id);

  }

}    
   


此时我们的代码写完了 功能上来讲 没毛病,但是从规范性的角度将 不合适。因为四个参数分别是 abcd 没有语义。
所以我们最好让参数有语义化。

public class People {

   int   id;
   String  name;
   String  address;
   int   age;

   public People(int  id,String  name,String  address ,int age){
       id = id;
       name = name;
       address = address;
       age = age;
  }

}

但是又出现了另一个问题,局部变量和成员变量重名 此时编译器不知道哪个赋值给哪个,所以我们需要标记一下
public class People {

   int   id;
   String  name;
   String  address;
   int   age;

   public People(int  id,String  name,String  address ,int age){
       this.id = id;
       this.name = name;
       this.address = address;
       this.age = age;
  }

}
可以自动生成

1.14 函数的重载


我们添加了有参数的构造函数  此时无参数就不会自动生成,现在我就想用无参数的 怎么办?
   
解决方案 我们添加了有参数的构造函数  同时也添加无参数的构造函数

public class People {

   int   id;
   String  name;
   String  address;
   int   age;

   public People(){}

   public People(int id, String name, String address, int age) {
       this.id = id;
       this.name = name;
       this.address = address;
       this.age = age;
  }


}
此时我们又发现一个神奇的问题,一个类中 有俩函数同名了 还能共存 此时我们需要知道 在java中函数名相同并且能共存的语法规则是什么?
在java的一个类中,函数名相同 参数列表不同 则函数可以共存,并且这个语法就称之为  函数重载  英文名字  overload
参数列表不同指的是:
   A 参数的个数
   public class People {
       public void eat(int  a) { }
       public void eat(int  a,int  b) { }
  }

   B 参数的类型
   public class People {
        public void eat(int  a) { }
        public void eat(double  a) { }
  }
   C 参数顺序
public class People {
   public void eat(int  a ,double  b) { }
   public void eat(double  b ,int a) { }
}


为什么/什么场景中使用函数的重载?
   
我们目前遇到的重载场景    
public static void main(String[] args) {
       System.out.println(10);
       System.out.println(10.5);
       System.out.println(true);
       System.out.println('1');
       System.out.println("asdfjk");
}
println 这个函数就很神奇  我们的函数 是int类型 就传递int类型的参数 我们突然发现println这个函数 不仅能传递 int类型的 还能传递 double  boolean  char
   String 为什么他能什么类型的都传递呢? 我们使用 ctrl+左键
   public void println(boolean x) {
       synchronized (this) {
           print(x);
           newLine();
      }
  }
   public void println(char x) {
       synchronized (this) {
           print(x);
           newLine();
      }
  }
   public void println(int x) {
       synchronized (this) {
           print(x);
           newLine();
      }
  }
   public void println(long x) {
       synchronized (this) {
           print(x);
           newLine();
      }
  }
   public void println(float x) {
       synchronized (this) {
           print(x);
           newLine();
      }
  }

   public void println(double x) {
       synchronized (this) {
           print(x);
           newLine();
      }
  }


假如说 没有重载这个语法  一个类中函数名不能相同  现在我们需要输出 int  float  double ....每一个类型都得有一个方法  
printlnInt(int  a) printlnFloat(int  a)
现在有重载这个语法 println(int a) println(float a)
   
什么场景中我们可以使用重载进行优化:
  同一个函数需要传递不同类型的参数 实现不同的功能
  public static void main(String[] args) throws Exception {

       new FileOutputStream("D:/asd/asd.txt");
       new FileOutputStream("D:/asd/asd.txt",true);

  }
  同一个函数 实现相同的功能 但是希望能传递不同类型的参数
       System.out.println(10);
       System.out.println(10.5);
       System.out.println(true);
       System.out.println('1');
       System.out.println("a会改好价格+");  

1.15 set函数


我们之前写的代码有问题


public static void main(String[] args) {

      People p1 = new People();

      p1.id = 66;
      p1.name = "张三";
      p1.age = -18;

}

此时年龄是-18 从语法的角度将没毛病 因为 int类型 取值范围包含-18  但是从实际意义上讲 有问题 人类的年龄怎么可能出现负数
此时有的人说 要判断,对 ,要判断,但是 如果我需要创建50个people 每个人都有年龄 ,此时每个人都需要判断
太麻烦了 按照面向对象的思想 我们需要将重复代码写到一个函数中,然后通过调用函数的形式给其赋值

public class People {

   int   id;
   String  name;
   String  address;
   int   age;


   public People(){}
   public People(int id, String name, String address, int age) {
       this.id = id;
       this.name = name;
       this.address = address;
       this.age = age;
  }
   

   public void setAge(int  age){
       if(age > 0){
           this.age = age;
      }else{
           this.age = 0;
      }
  }


}


public class JavaTest {

   public static void main(String[] args) {

      People p1 = new People();

      p1.id = 66;
      p1.name = "张三";
      p1.setAge(-18);

  }


}

1.16 权限修饰符


我们刚才操作了set函数 给成员变量设置值
public static void main(String[] args) {
      People p1 = new People();
      p1.setAge(-18);
}
确保了数据的准确性,但是依然存在直接打点调用的赋值形式,此时依然会出现错误
public static void main(String[] args) {
       People p1 = new People();
       p1.age = -18;
}
如何解决这个问题?
让打点调用赋值的形式无法调用即可
   
如何不让其打点调用赋值呢?
使用私有的修饰符进行修饰
private int   age;

权限修饰符

public                公共的,修饰的内容在当前工程的任意包中都能访问。
                     修饰的内容:成员变量  函数  
   
protected             包权限+继承权限,修饰的内容只能在当前包中使用,如果不在同一个包,但是两个类有继承关系,也可以访问。
                     修饰的内容:成员变量  函数
   
default/friendly      包权限,修饰的内容只能在当前包中使用,其他包无法访问。
                     注意:包权限不是写default关键 而是什么都不写代表包权限
                     修饰的内容:成员变量  函数  
   
private               私有的,修饰的内容只能在本类中访问,外部无法访问。
                     修饰的内容:成员变量  函数  

1.17 get函数


我们设置了set函数并且将成员变量私有化、此时可以保证赋值的准确性,但是我们之前也说过,对象是用来存取数据的。能存还得能取,但是现在只能存不能取

public static void main(String[] args) {

       People p1 = new People();
       p1.setAge(18);

       System.out.println(p1.age);
}
此时age私有化了 获取不了
有人说 将私有化干掉
所以我们需要一个函数用来获取私有化成员变量的值 --- get函数

public int getAge(){
       return age;
}


此时就可以使用get函数获取对象的值
public static void main(String[] args) {

       People p1 = new People();
       p1.setAge(18);

       int a =  p1.getAge();
       System.out.println(a);
}


1.18 toString函数


我们创建完成对象
 public static void main(String[] args) {

       People p1 = new People(666,"张三","北京",18);

       System.out.println(p1);

  }
想要输出以下对象,我们想着输出人的信息 但是输出的是com.aaa.day02.test2.People@1540e19d
这是 当前对象所属类的全限定名@hashcode
所以我们希望让其输出成我们想要的格式

为什么输出这个样子 ?因为在输出的时候 System.out.println(p1); 输出的是对象的toString返回值
所以我们希望其输出的格式 就需要重写其toString函数

public class People {

   int   id;
   String  name;
   String  address;
   int   age;

   public People(){}
   public People(int id, String name, String address, int age) {
       this.id = id;
       this.name = name;
       this.address = address;
       this.age = age;
  }

   @Override
   public String toString(){
       return "id的值:"+id+" name的值:"+name + " address的值:"+address + " age的值:"+age;
  }

}

1.19 数据模型类的自动生成


以后我们使用对象存储数据 有一套固定的模式 是经过长期的经验总结出来的
假如说存储一个人的信息    编号  名字  年龄  地址
A 创建一个类(建明之一)
public class People {}

B 根据需要存储的信息 创建私有化的成员变量
public class People {

   private   int  id;
   private   String  name;
   private   int  age;
   private   String  address;

}

C 使用快捷键 给其生成 构造函数 set和get  toString  

public class People {

   private   int  id;
   private   String  name;
   private   int  age;
   private   String  address;


   public People() {}

   public People(int id, String name, int age, String address) {
       this.id = id;
       this.name = name;
       this.age = age;
       this.address = address;
  }

   public int getId() {
       return id;
  }

   public void setId(int id) {
       this.id = id;
  }

   public String getName() {
       return name;
  }

   public void setName(String name) {
       this.name = name;
  }

   public int getAge() {
       return age;
  }

   public void setAge(int age) {
       this.age = age;
  }

   public String getAddress() {
       return address;
  }

   public void setAddress(String address) {
       this.address = address;
  }

   @Override
   public String toString() {
       return "People{" +
               "id=" + id +
               ", name='" + name + '\'' +
               ", age=" + age +
               ", address='" + address + '\'' +
               '}';
  }
}

1.20 对象的封装


封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;
   
我们的封装其实分成两种方式:  
   A 数据模型类的封装  
      封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;
   
   B 功能函数类的封装

 

posted @ 2021-11-15 18:06  吴光熠  阅读(18)  评论(0)    收藏  举报