Java之类 #类的属性 #类的方法(#方法的重载 #可变形参的方法 #方法参数的值传递机制 #递归方法)#类的构造方法 #类的代码块 #内部类 #UML类库

发布于:2022-11-15 ⋅ 阅读:(664) ⋅ 点赞:(0)
  • 类的成员之——属性

语法格式:

修饰符 数据类型 属性名 = 初始化值 ;
说明1: 修饰符
    常用的权限修饰符有:private、缺省、protected、public
    其他修饰符:static、final (暂不考虑)
说明2:数据类型
    任何基本数据类型(如int、Boolean) 或 任何引用数据类型。
说明3:属性名
    属于标识符,符合命名规则和规范即可。
 public class Student{
        public String name;
        private int age = 18;
    }

属性可以赋值的位置

①默认初始化
②显式初始化/⑤在代码块中赋值
③构造器中初始化
④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值 
执行的先后顺序:① - ② / ⑤ - ③ - ④

属性(成员变量)与局部变量

 1.相同点:
         1.1  定义变量的格式:数据类型  变量名 = 变量值
          1.2 先声明,后使用
          1.3 变量都有其对应的作用域  
 2.不同点:
          2.1 在类中声明的位置的不同
          属性:直接定义在类的一对{}内
          局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
          
         2.2 关于权限修饰符的不同
         属性:可以在声明属性时,指明其权限,使用权限修饰符。
                    常用的权限修饰符:private、public、缺省、protected  --->封装性
         局部变量:不可以使用权限修饰符。
 
         2.3 默认初始化值的情况:
         属性:类的属性,根据其类型,都有默认初始化值。
             整型(byte、short、int、long):0
             浮点型(float、double):0.0
             字符型(char):0  (或'\u0000')
             布尔型(boolean):false
             引用数据类型(类、数组、接口):null
         局部变量:没有默认初始化值。 意味着,我们在调用局部变量之前,一定要显式赋值。
         特殊:形参在调用时,我们赋值即可。

         2.4 在内存中加载的位置:
         属性:加载到堆空间中   (非static)
         局部变量:加载到栈空间

  •  类的成员之——方法

方法的声明格式

修饰符 返回值类型 方法名(参数类型 形参1, 参数类型 形参2, ….){
方法体程序代码
return 返回值;

说明

1 权限修饰符:Java规定的4种权限修饰符:private、public、缺省、protected 
2 返回值类型: 有返回值  vs 没有返回值
    2.1  如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。
    2.2 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。
3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
4 形参列表: 方法可以声明0个,1个,或多个形参。
    4.1 格式:数据类型1 形参1,数据类型2 形参2,...
    4.2 我们定义方法时,该不该定义形参?(具体问题具体分析)
5 方法体:方法功能的体现。         
6 return关键字的使用:
    6.1 使用范围:使用在方法体中
    6.2 作用:① 结束方法
                     ② 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。
    6.3 注意点:return关键字后面不可以声明执行语句
7 方法的使用中,可以调用当前类的属性或方法
    7.1 特殊的:方法A中又调用了方法A:递归方法。
    7.2 方法中,不可以定义方法。

方法的重载

定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
遵循原则:两同一不同原则:同一个类、相同方法名 ;参数列表不同:参数个数不同,参数类型不同

Test :比较三个数,输出其中最大数(运用方法重载,可满足不同类型)

class GetMax{
    public static void main(String[] args) {
        GetMax test = new GetMax();
        System.out.println(test.getMax(11, 22, 33));
    }
    public int getMax(int i,int j,int c){
        int max =  (i > j) ? i : j;
        return (max > c) ? max : c;
    }

    public double getMax(double i,double j,double c){
        double max =  (i > j) ? i : j;
        return (max > c) ? max : c;
    }
}

方法的可变个数的形参(jdk 5.0新增的内容)

1 可变个数形参的格式:数据类型 ... 变量名
2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
5 可变个数形参在方法的形参中,必须声明在末尾
6  可变个数形参在方法的形参中,最多只能声明一个可变形参。

public class MethodArgs {
    public static void main(String[] args) {
        MethodArgs test = new MethodArgs();
        test.print(12);
        test.print("12");
        test.print("12","13","14");
        //等同于上边
        test.print(new String[]{"12","13","14"});
    }

    public void print(int i){
        System.out.println("输入的【" + i + "】为int类型");
    }

    public void print(String s){
        System.out.println("输入的【" + s + "】为String类型");
    }

    public void print(String ... str){
        for (int i = 0; i < str.length; i++) {
            System.out.println("输入的【" + str[i]  + "】为String...类型");
        }
    }

   /*不能与上一个方法同时存在
    public void print(String[] str){
        System.out.println("输入为String...类型");
    }*/
}
//  public void print(String ...str,int i){  //可变个数形参必须放在末尾
    public void print(int i,String ...str){
        System.out.println("可变个数形参必须放在末尾");
    }

方法参数的值传递机制(值传递)

方法,必须由其所在类或对象调用才有意义。若方法含有参数:

形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据

Java 里方法的参数传递方式只有一种: 值传递 。 即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。
* 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
* 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
class ValueTransfer{
    public static void main(String[] args) {
        Student1[] arr = new Student1[10];//声明Student1类型的数组
        for (int i = 0; i < arr.length; i++) {
            arr[i] = new Student1();//给数组元素赋值
            arr[i].score = (int)(Math.random() * (100-0 +1) +0);//给Student1对象的属性(成绩)赋值(0-100的随机数)
        }
        //按成绩冒泡排序
        ValueTransfer test = new ValueTransfer();
        for (int i = 0; i < arr.length -1; i++) {
            for (int j = 0; j < arr.length -1 -i; j++) {
                //如果需要换序,交换的是数组的元素:Student对象!!!(不要把成绩交换了)
                if (arr[j].score > arr[j+1].score){
//                    test.swap(j,j+1);  //所以属于基本数据类型 为数据值传递 不能通过中间变量交换(比如a=10,b=a,b=20,a=?还是10)
//                    test.swap(arr[i],arr[i+1]);//数组的元素是基本数据类型 是数据值传递
                    test.swap(arr,j,j+1);//引用数据类型是地址值传递
                }
            }
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i].score);
        }
    }

    /**
     * @description 交换数组中指定位置的二个元素的值
     * @author ALvin
     * @date 2022年1月11日10:18:38
     * param
     */
    public void swap(int i,int j){
        int temp = i;
        i = j;
        j = temp;
    }
    public void swap(Student1 i,Student1 j){
        Student1 temp = i;
        i = j;
        j = temp;
    }
    public void swap(Student1[] st,int i,int j){
        Student1 temp = st[i];
        st[i] = st[j];
        st[j] = temp;
    }
}

class Student1{
    int score;//成绩
}

递归方法

递归方法:一个方法体内调用它自身

注意:方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
           递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
class Recursion{
    public static void main(String[] args) {
        Recursion test = new Recursion();
        System.out.println(test.getSum(3));
    }
    public int getSum(int n){
        if(n == 1){
            return 1;
        }else {
            return n * getSum(n-1);
        }
    }
}
  • 类的构造方法(构造器) 

作用:1.创建对象  2.初始化对象的信息

特征:1.它具有与类相同的名称  2.它不声明返回值类型。(与声明为void不同) 3.不能被staticfinalsynchronizedabstractnative修饰,不能有return语句返回值

说明: 

1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
2.定义构造器的格式:权限修饰符  类名(形参列表){}
3.一个类中定义的多个构造器,彼此构成重载
4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
5.一个类中,至少会有一个构造器。

public class Java1 {
    public static void main(String[] args) {
        //创建类的对象:new + 空参构造器
        Person p = new Person();
        p.setName("张三");
        p.eat();
        p.study();
        //创建类的对象:new + 有参构造器
        Person p1 = new Person("李四");
        p1.eat();
        p1.study();
    }
}

class Person{
    private String name;//名字(private只能在本类中使用)
    private int age;//年龄

    //空参构造
    public  Person(){}
    //有参构造
    public Person(String name) {
        this.name = name;
    }

    //定义属性的get,set方法
    public String getName() {
        return name;
    }

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

    //方法
    public void eat(){
        System.out.println(name + "吃饭");
    }

    public void study(){
        System.out.println(name+ "学习");
    }
}
  • 类的成员之——代码块 (或初始化块)

1. 代码块的作用:用来初始化类、对象
2. 代码块如果有修饰的话,只能使用static.
3 分类:静态代码块  vs 非静态代码块
4. 静态代码块
         >内部可以有输出语句
         >随着类的加载而执行,而且只执行一次
         >作用:初始化类的信息
         >如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
         >静态代码块的执行要优先于非静态代码块的执行
         >静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
5. 非静态代码块
          >内部可以有输出语句
          >随着对象的创建而执行
          >每创建一个对象,就执行一次非静态代码块
          >作用:可以在创建对象时,对对象的属性等进行初始化
          >如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
          >非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

6. 执行顺序:由父及子 静态先行 

public class BlockTest {
    public static void main(String[] args) {
        Animal a = new Animal();
        System.out.println(a);
    }
}

class Animal{
    String name;
    int age;
    static String desc = "动物"; //静态属性 全类通用

    //构造器
    public Animal(){}

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //非静态代码块
    {
        name = "小狗";
        age = 3;
        desc = "我是一只小狗";
        show();
        toString();
    }

    //静态代码块
    static {
        //静态代码块不能调用非静态变量
//        name = "小狗";
//        age = 3;
        desc = "我是一只小狗1";
        show();
//        toString;  //静态代码块不能调用非静态方法
        System.out.println(desc);
    }

    //方法
    public String toString(){
        return "name=" + name + ",age=" +age;
    }

    public static void show(){
        System.out.println("Static方法");
    }
}

//执行结果:
//Static方法
//我是一只小狗1
//Static方法
//name=小狗,age=3
  • 类的成员之——内部类 

内部类的定义和使用规范

1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
2. 内部类的分类:成员内部类(静态、非静态)  vs 局部内部类(方法内、代码块内、构造器内)
3. 成员内部类:
          一方面,作为外部类的成员:
              >调用外部类的结构
              >可以被static修饰
              >可以被4种不同的权限修饰
          另一方面,作为一个类:
              > 类内可以定义属性、方法、构造器等
              > 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
              > 可以被abstract修饰

public class InnerClassTest {
    public static void main(String[] args) {
        //创建Dog实例(静态的成员内部类):
        Animal.Dog dog = new Animal.Dog();
        dog.eat();
        dog.show();
        //创建Pig实例(非静态的成员内部类):
        Animal anm = new Animal();
        anm.name = "八戒";
        Animal.Pig pig = anm.new Pig();
        pig.name = "二白";
        pig.eat();
        pig.show("佩奇");
    }
}

class Animal{
    String name;

    public void eat(){
        System.out.println("进食");
    }

    //静态成员内部类
    static class Dog{
        public void eat(){
            System.out.println("小狗吃饭");
        }
        public void show(){
            System.out.println("小狗");
//            Animal.this.eat(); //静态类中不能引用非静态方法
            eat();
        }
    }

        //非静态成员内部类
        class Pig{
        String name;

        public void eat(){
            System.out.println("小猪吃饭");
        }

        public void show(String name){
            System.out.println("小猪");
            Pig.class.getClass();
            Animal.this.eat();
            System.out.println(name);//方法的形参
            System.out.println(this.name);//内部类的形参
            System.out.println(Animal.this.name);//外部类的形参
        }
    }
}

//执行结果
/*
小狗吃饭
小狗
小狗吃饭
小猪吃饭
小猪
进食
佩奇
二白
八戒
*/

4. 局部内部类:                                                                                                                                          4.1 只能在声明它的方法或构造器或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
         4.2 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
         4.3 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
         4.4 局部内部类可以使用外部类的成员,包括私有的。
         4.5 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
         4.6 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
         4.7 局部内部类不能使用static修饰,因此也不能包含静态成员

public class InnerClassTest1 {
    public static void main(String[] args) {
        Person1 p = new Person1();
        p.name = "老李";
        p.eat();
    }
}

class Person1{
    String name;

    {
        //定义在代码块中的局部内部类
        class CC{
            public void disPlay(){
                System.out.println("定义在代码块中的局部内部类");
                System.out.println(name);
            }
        }
    }

    public Person1(){
        //定义在构造器的局部内部类
        class AA {
            public void disPlay1() {
                System.out.println("定义在构造器中的局部内部类");
                System.out.println(name);
            }
        }
    }

    public void eat(){
        int num = 10;
        System.out.println("吃饭");
        //局部内部类(方法中)
//       public class BB {  //不能使用 public,protected,缺省,private 来修饰
        class BB {
            public void disPlay(String name) {
                System.out.println("定义在方法中的局部内部类");
                System.out.println(name);//方法的形参
                System.out.println(Person1.this.name);//外部类的name属性
                System.out.println(num + 1);//调用外部方法的局部变量
            }
        }
        //先声明,后使用
        BB bb = new BB();
        bb.disPlay("老王");
    }
}

//执行结果
/*
吃饭
定义在方法中的局部内部类
老王
老李
11
*/

5. 重点关注如下的3个问题
         5.1 如何实例化成员内部类的对象
         5.2 如何在成员内部类中区分调用外部类的结构
         5.3 开发中局部内部类的使用   

  • 拓展 ——UML类图

说明:1.  + 表示 public 类型, - 表示 private 类型, # 表示 protected 类型
           2.   方法的写法 : 方法的类型(+ -) 方法名 ( 参数名: 参数类型 ) :返回值类型

说明:本篇文章部分内容和图片引用尚硅谷官网内容,特此说明。@尚硅谷官网地址


网站公告

今日签到

点亮在社区的每一天
去签到