面向对象三大特征之封装

1.成员变量和局部变量的区别

(1).在类中的位置不同

成员变量: 在类中方法外

局部变量: 在方法定义中,或方法声明上

(2).在内存中的位置不同

成员变量: 在堆内存

局部变量: 在栈内存

(3).生命周期不同

成员变量: 随着对象的创建而存在,随着对象的消失而消失

局部变量: 随着方法的调用而存在,随着方法的调用完毕而消失

(4).初始化值不同

成员变量: 有默认初始化值
byte,short,int,long–>0;float,double–>0.0;char–>\u0000;boolean–>false

局部变量:没有默认初始化值,必须定义,赋值,然后才能使用

注意事项

局部变量名称可以和成员变量名称相同,在方法中使用的时候,采用的是就近原则;

代码示例

  class Varialbe {
    //成员变量
    //int num = 10;
    int num; //0

    public void show() {
        //int num2 = 20; //局部变量
        //可能尚未初始化变量num2
        //int num2; //没有默认值
        int num2 = 20;
        System.out.println(num2);

        //int num = 100;
        System.out.println(num);
    }
}


class VariableDemo {
    public static void main(String[] args) {
        Varialbe v = new Varialbe();

        System.out.println(v.num); //访问成员变量

        v.show();   

    }
}

2.类作为形式参数传递的问题

如果一个方法需要传递的参数是一个类名,那么这里实际需要传递的是一个具体的对象;

代码示例

/*
    形式参数的问题:
        基本类型:形式参数的改变不影响实际参数
        引用类型:形式参数的改变直接影响实际参数
*/
//形式参数是基本类型
class Demo {
    public int sum(int a,int b) {
        return a + b;
    }
}

//形式参数是引用类型
class Student {
    public void show() {
        System.out.println("我爱学习");
    }
}

class StudentDemo {
    //如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
    public void method(Student s) { //调用的时候,把main方法中的s的地址传递到了这里 Student s = new Student();
        s.show();
    }
}

class ArgsTest {
    public static void main(String[] args) {
        //形式参数是基本类型的调用
        Demo d = new Demo();
        int result = d.sum(10,20);
        System.out.println("result:"+result);
        System.out.println("--------------");

        //形式参数是引用类型的调用
        //需求:我要调用StudentDemo类中的method()方法
        StudentDemo sd = new StudentDemo();
        //创建学生对象
        Student s = new Student();
        sd.method(s); //把s的地址给到了这里
    }
}

3.匿名对象

(1).概念

没有名字的对象

(2).应用场景

调用方法,仅仅是调用一次的时候;

可以作为实际参数传递

代码示例
/*
    匿名对象:就是没有名字的对象。

    匿名对象的应用场景:
        A:调用方法,仅仅只调用一次的时候。
            注意:调用多次的时候,不适合。
            那么,这种匿名调用有什么好处吗?
                有,匿名对象调用完毕就是垃圾。可以被垃圾回收器回收。
        B:匿名对象可以作为实际参数传递
*/
class Student {
    public void show() {
        System.out.println("我爱学习");
    }
}

class StudentDemo {
    public void method(Student s) {
        s.show();
    }
}

class NoNameDemo {
    public static void main(String[] args) {
        //带名字的调用
        Student s = new Student();
        s.show();
        s.show();
        System.out.println("--------------");

        //匿名对象
        //new Student();
        //匿名对象调用方法
        new Student().show();
        new Student().show(); //这里其实是重新创建了一个新的对象
        System.out.println("--------------");


        //匿名对象作为实际参数传递
        StudentDemo sd = new StudentDemo();
        //Student ss = new Student();
        //sd.method(ss); //这里的s是一个实际参数
        //匿名对象
        sd.method(new Student());

        //在来一个
        new StudentDemo().method(new Student());
    }
}

4.封装

(1).概念

隐藏对象的属性和实现细节,仅对外提供公共的访问方式

(2).好处

隐藏实现细节,提供公共的访问方式

提高代码的复用性

提高代码的安全性

(3).设计原则

把不想让外界知道的实现细节隐藏起来,仅提供公共的访问方式

(4).具体体现

private是封装的具体体现,用private来修饰类的成员变量和成员方法

代码示例

/*
    定义一个学生类:
        成员变量:name,age
        成员方法:show()方法

    我们在使用这个案例的过程中,发现了一个问题:
        通过对象去给成员变量赋值,可以赋值一些非法的数据。
        这是不合理的。
        应该是这个样子的:在赋值之前,先对数据进行判断。
        判断到底在哪里做比较合适呢?
        StudentDemo类是一个测试类,测试类一般只创建对象,调用方法。 
        所以,这个判断应该定义在Student类中。
        而我们在成员变量的位置可不可以进行数据判断呢?
        是不可以的,因为做数据校验,必须要依靠一些逻辑语句。
        逻辑语句是应该定义在方法中的,所以,我们最终决定在Student类中提供一个方法
        来对数据进行校验。

    按照我们前面的分析,我们给出了一个方法进行校验。
    但是呢,它偏偏不调用方法来赋值,还是直接赋值了,
    这样我们的方法就没有起到作用。
    我就应该要求你必须使用我的方法,而不能直接调用成员变量赋值。
    怎么去强制要求不能直接使用成员变量呢?
        针对这种情况,Java就提供了一个关键字 private

    private:私有的。可以修饰成员变量和成员方法。
        注意:被private修饰的成员只能在本类中访问。

    其实我讲到现在讲解的是一个封装的思想。
    封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
*/
class Student {
    //姓名
    String name;
    //年龄
    private int age;

    //写一个方法对数据进行校验
    /*
        返回值类型:void
        参数列表:int a
    */
    public void setAge(int a) {
        if(a < 0 || age > 120) {
            System.out.println("你给的年龄有问题");
        }else {
            age = a;
        }
    }


    //show()方法,显示所有成员变量值
    public void show() {
        System.out.println("姓名:"+name);
        System.out.println("年龄:"+age);
    }
}

class StudentDemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();
        s.show();
        System.out.println("--------------");

        //给成员变量赋值
        s.name = "林青霞";
        //s.age = 27;
        s.setAge(27);
        s.show();
        System.out.println("--------------");

        //给age赋值
        //s.age = -27; //这个数据是不合理的
        //通过方法给值
        s.setAge(-27);
        s.show();
        System.out.println("--------------");
    }
}

5.private关键字

(1).意义

可以修饰成员变量和成员方法,防止外界直接使用

(2).特点

被private修饰后的成员,只能在本类中访问

(3).应用

写类的时候,把所有的成员变量用private修饰,并提供对应的setXXX/getXXX方法

代码示例

/*
    封装和private的应用:
        A:把成员变量用private修饰
        B:提高对应的getXxx()和setXxx()方法
*/
//定义学生类
class Student {
    //姓名
    private String name;
    //年龄
    private int age;

    //姓名获取值
    public String getName() {
        return name;
    }

    //姓名设置值
    public void setName(String n) {
        name = n;
    }

    //年龄获取值
    public int getAge() {
        return age;
    }

    //年龄赋值
    public void setAge(int a) {
        age = a;
    }

    public void show() {
        System.out.println(num);
    }

    private void method() {
        System.out.println("method");
    }

    public void function() {
        method();
    }
}

//测试类
class StudentTest {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();

        //使用成员变量
        //错误:被私有修饰了,外界不能直接访问了
        //System.out.println(s.name+"---"+s.age);
        System.out.println(s.getName()+"---"+s.getAge());

        //给成员变量赋值
        //s.name = "林青霞";
        //s.age = 27;
        //通过方法给赋值
        s.setName("林青霞");
        s.setAge(27);
        System.out.println(s.getName()+"---"+s.getAge());
    }

        d.show();
        //不能访问私有的成员方法
        //d.method();
        d.function();
}

6.this关键字

(1).意义

代表当前类的引用对象,哪个对象调用方法,该方法内部的this就代表那个对象

(2).应用场景

解决了局部变量隐藏成员变量的问题

(3).内存图

这里写图片描述

代码示例

/*
    我们曾经曰:起名字要做到见名知意。

    this:是当前类的对象引用。简单的记,它就代表当前类的一个对象。

        注意:谁调用这个方法,在该方法内部的this就代表谁。

    this的场景:
        解决局部变量隐藏成员变量
*/
//定义学生类
class Student {
    //姓名
    private String name;
    //年龄
    private int age;

    //姓名获取值
    public String getName() {
        return name;
    }

    //姓名设置值
    public void setName(String name) { //name = "林青霞";
        //name = name; //变量的使用规则:就近原则
        //这里是类名,目前还没有说过类似的用法,所以这个是有问题的
        //这里的调用只能通过对象名
        //这个对象如果存在,它应该代表的是Student的一个对象。
        //那么,谁能够代表当前类的对象呢? java就提供了一个关键字 this
        //Student.name = name;
        this.name = name;
    }

    //年龄获取值
    public int getAge() {
        return age;
    }

    //年龄赋值
    public void setAge(int age) {
        this.age = age;
    }
}

//测试类
class StudentTest {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();

        //给成员变量赋值
        s.setName("林青霞");
        s.setAge(27);
        //获取数据
        System.out.println(s.getName()+"---"+s.getAge());
    }
}

7.构造方法

(1)作用

用于对对象的数据进行初始化

(2)格式

方法名和类名相同

没有返回值类型,连void都不能有

没有返回值

(3)注意事项

如果我们没写构造方法,系统将提供一个默认的无参构造方法

如果我们给出了构造方法,系统将不再提供默认构造方法.如果这个时候,我们要使用无参构造方法,就必须自己给出。建议永远自己手动给出无参构造方法。

(4)给成员变量赋值的方式

setXxx()

带参构造方法

代码示例

/*
    我们一直在使用构造方法,但是,我们确没有定义构造方法,用的是哪里来的呢?

    构造方法的注意事项:
        A:如果我们没有给出构造方法,系统将自动提供一个无参构造方法。
        B:如果我们给出了构造方法,系统将不再提供默认的无参构造方法。
            注意:这个时候,如果我们还想使用无参构造方法,就必须自己给出。建议永远自己给出无参构造方法

    给成员变量赋值有两种方式:
        A:setXxx()
        B:构造方法
*/

class Student {
    private String name;
    private int age;

    public Student() {
        //System.out.println("我给了,你还给不");
        System.out.println("这是无参构造方法");
    }

    //构造方法的重载格式
    public Student(String name) {
        System.out.println("这是带一个String类型的构造方法");
        this.name = name;
    }

    public Student(int age) {
        System.out.println("这是带一个int类型的构造方法");
        this.age = age;
    }

    public Student(String name,int age) {
        System.out.println("这是一个带多个参数的构造方法");
        this.name = name;
        this.age = age;
    }

    public void show() {
        System.out.println(name+"---"+age);
    }
}

class ConstructDemo2 {
    public static void main(String[] args) {
        //创建对象
        Student s = new Student();
        s.show();
        System.out.println("-------------");

        //创建对象2
        Student s2 = new Student("林青霞");
        s2.show();
        System.out.println("-------------");

        //创建对象3
        Student s3 = new Student(27);
        s3.show();
        System.out.println("-------------");

        //创建对象4
        Student s4 = new Student("林青霞",27);
        s4.show();
    }
}

8.创建对象的过程

Student s = new Student();做了哪些事情?

(1).把Student.class文件加载到内存

(2).在栈内存为s开辟空间

(3).在堆内存为学生对象申请空间

(4).给学生的成员变量进行默认初始化。

(5).给学生的成员变量进行显示初始化。

(6).通过构造方法给成员变量进行初始化。

(7).对象构造完毕,把地址赋值给s变量

9.static关键字

(1).作用

可以修饰成员变量和成员方法。

(2).特点

随着类的加载而加载

优先与对象存在

被类的所有对象共享,这也是我们判断该不该使用静态的依据。

既可以通过对象名调用,也可以通过类名调用,建议通过类名调用。

(3)内存图

静态的内容在方法区的静态区

这里写图片描述

(4).注意事项;

在静态方法中没有this对象

静态只能访问静态

代码示例
/*
    static关键字注意事项
        A:在静态方法中是没有this关键字的
            如何理解呢?
                静态是随着类的加载而加载,this是随着对象的创建而存在。
                静态比对象先存在。
        B:静态方法只能访问静态的成员变量和静态的成员方法
                静态方法:
                    成员变量:只能访问静态变量
                    成员方法:只能访问静态成员方法
                非静态方法:
                    成员变量:可以是静态的,也可以是非静态的
                    成员方法:可是是静态的成员方法,也可以是非静态的成员方法。
            简单记:
                静态只能访问静态。
*/
class Teacher {
    public int num = 10;
    public static int num2 = 20;

    public void show() {
        System.out.println(num); //隐含的告诉你访问的是成员变量
        System.out.println(this.num); //明确的告诉你访问的是成员变量
        System.out.println(num2);

        //function();
        //function2();
    }

    public static void method() {
        //无法从静态上下文中引用非静态 变量 num
        //System.out.println(num);
        System.out.println(num2);

        //无法从静态上下文中引用非静态 方法 function()
        //function();
        function2();
    }

    public void function() {

    }

    public static void function2() {

    }
}

class TeacherDemo {
    public static void main(String[] args) {
        //创建对象
        Teacher t = new Teacher();
        t.show();
        System.out.println("------------");
        t.method();
    }
}

(5).静态变量和成员变量的区别

所属不同

静态变量:属于类,类变量

成员变量:属于对象,对象变量,实例变量

内存位置不同

静态变量:方法区的静态区

成员变量:堆内存

生命周期不同

静态变量:静态变量是随着类的加载而加载,随着类的消失而消失

成员变量:成员变量是随着对象的创建而存在,随着对象的消失而消失

调用不同

静态变量:可以通过对象名调用,也可以通过类名调用

成员变量:只能通过对象名调用

(6).main方法是静态的

public:权限最大

static:不用创建对象调用

void:返回值给jvm没有意义

main:就是一个常见的名称。

String[] args:可以接收数据,提供程序的灵活性

代码示例
/*
    main方法的格式讲解:
        public static void main(String[] args) {...}

        public:公共的,访问权限是最大的。由于main方法是被jvm调用,所以权限要够大。
        static:静态的,不需要创建对象,通过类名就可以。方便jvm的调用。
        void:因为我们曾经说过,方法的返回值是返回给调用者,而main方法是被jvm调用。你返回内容给jvm没有意义。
        main:是一个常见的方法入口。我见过的语言都是以main作为入口。
        String[] args:这是一个字符串数组。值去哪里了?
            这个东西到底有什么用啊?怎么给值啊?
                这个东西早期是为了接收键盘录入的数据的。
                格式是:
                    java MainDemo hello world java
*/
class MainDemo {
    public static void main(String[] args) {
        //System.out.println(args); //[Ljava.lang.String;@175078b
        //System.out.println(args.length); //0
        //System.out.println(args[0]); //ArrayIndexOutOfBoundsException

        //接收数据后
        System.out.println(args); 
        System.out.println(args.length); 
        //System.out.println(args[0]); 
        for(int x=0; x<args.length; x++) {
            System.out.println(args[x]);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值