Java学习笔记02--成员变量和局部变量、构造函数、构造代码块、this关键字、static关键字、静态函数

时间:2023-02-11 18:08:44

成员变量和局部变量

  1. 自定义的位置区别:

    • 成员变量是定义在方法之外,类之内的变量。

    • 局部变量是声明在方法之内的变量。

  2. 作用上的区别:

    • 成员变量的作用描述一类事物的属性。

    • 局部变量的作用是提供一个变量给方法内部使用的。

  3. 生命周期的区别;

    • 成员变量随着对象的创建而存在,随着对象的消失而消失。
    • 局部变量是调用到了对应的方法执行 到了创建该变量的语句时存在,一旦出了自己的作用域马上从内存中消失。
  4. 初始值的区别:

    • 成员变量是有默认的初始值的。
    • 局部变量是没有默认的初始值的,必须要先初始化才能使用。

构造函数

java构造函数函数详解

构造函数的作用: 给对应的对象进行初始化。

构造函数的定义的格式:

修饰符  函数名(形式参数){
    函数体...
}

构造函数要注意的细节:
1. 构造函数 是没有返回值类型的。
2. 构造函数的函数名必须要与类名一致。
3. 构造函数并不是由我们手动调用的,而是在创建对应的对象时,jvm就会主动调用到对应的构造函数。
4. 如果一个类没有显式的写上一个构造方法时,那么java编译器会为该类添加一个无参的构造函数的。
5. 如果一个类已经显式的写上一个构造方法时,那么java编译器则 不会再为该类添加 一个无参 的构造方法。
6. 构造函数是 可以在一个类中以函数重载 的形式存在多个 的。

疑问:创建对象时,jvm就会调用到对应的构造方法,那么我们以前没有学构造方法,那么以前创建对象时,jvm是否 也会调用构造方法呢?如果有?构造方法从何而来呢?

会调用, java编译器在编译的 时候给加上去的。

构造函数与普通 函数的区别:

  • 返回值类型的区别:
    1. 构造函数是没有返回值类型 的,
    2. 普通函数是有返回值类型的,即使函数没有返回值,返回值类型也要写上void。
  • 函数名的区别:
    1. 构造函数的函数名必须要与类名一致,
    2. 普通函数的函数名只要符合标识符的命名规则即可。
  • 调用方式的区别:
    1. 构造函数是 在创建对象的时候由jvm调用的。
    2. 普通函数是由我们使用对象调用的,一个对象可以对象多次普通 的函数,
  • 作用上的区别:
    1. 构造函数 的作用用于初始化一个对象。
    2. 普通函数是用于描述一类事物的公共行为的。
//婴儿类
class Baby{

    int id; //身份证

    String  name;  //名字

    //构造函数
    public  Baby(int i , String n){
        id  = i;
        name = n;
        System.out.println("baby的属性初始化完毕!!");
    }

    //无参 的构造函数
    public Baby(){
        System.out.println("无参的构造函数被调用了..");
    }


    //哭
    public void cry(){
        System.out.println(name+"哇哇哭...");
    }   
}


class Demo2 
{
    public static void main(String[] args) 
    {   
        //创建一个baby对象
        Baby b1 =   new Baby(110,"狗娃"); //婴儿诞生 白户
        System.out.println("编号:"+ b1.id +" 姓名:"+ b1.name);
        b1.cry();
        b1.cry();



        /* //黑户 Baby b2 = new Baby(); new Baby(); b2.id = 112; b2.name = "狗剩"; System.out.println("编号:"+ b2.id +" 姓名:"+ b2.name); */
    }
}

iOS构造函数对比描述

1,概念
构造方法:指和类同名,用于构造对象(即生成对象)的方法;
实例方法:指的是在实例生成之后,实例调用的方法。
构造方法->构造实例;  
实例产生->调用实例方法。
详细说来,就是类调用构造方法,来生成了一个实例,而这个实例产生了以后,才会调用实例方法来完成一些行为。

2,两者之间的差异
行为差异:构造方法,创建对象后自动调用构造方法;
实例方法,必须已经存在对象,并调用实例方法。
功能差异:构造方法多用于初始化对象状态,对属性赋初值;
实例方法用于实现某个功能

3,举例说明
构造方法分为系统自带和自定义构造方法。
(1)如果是系统自带的构造方法,需要重写父类中自带的构造方法 比如init
(2)如果是自定义构造方法:属于对象方法那么以 - 号开头,返回值一般为id类型,方法名一般以init开头

/***************父类 Person.h文件*************************/
#import <Foundation/Foundation.h>
@interface Person : NSObject

// @property 默认生成的成员变量为@private类型子类无法直接访问 可以通过get/set方法访问
// 年龄
@property int age;
// 姓名
@property NSString *name;
// 自定义构造方法 在初始化的时候为属性"年龄"和"姓名"赋值
- (id)initWithAge:(int)age andName:(NSString *)name;
@end
/*************父类 Person.m文件 *****************************/
#import "Person.h"
@implementation Person

// 重写父类的init方法 父类init方法返回的是id类型就是为了让任何子类的对象调用
- (id)init
{
    // 1.首先初始化父类NSObject中声明的一些成员变量和属性 然后将初始化的对象赋值给当前对象
    self = [super init];
    // 2.如果父类的初始化成功 再初始化子类对象
    if (self!= nil) { // self是个指针 如果为空意味着指向0 也可以这样写 self != 0 
        _age = 10;
    }
    // 3.返回已经初始化完毕的对象
    return self;
}

// 实现自定义构造函数 在初始化的时候为属性赋值
- (id)initWithAge:(int)age andName:(NSString *)name
{
    if (self = [super init]) {
        _age = age;
        _name = name;
    }
    return self;
}
@end

构造代码块

构造代码块的作用:给对象进行统一的初始化。

构造函数的作用: 给对应的对象进行初始化。

构造代码块的格式:

{
    构造代码块
}

注意: 构造代码块的大括号必须位于成员 位置上。

代码块的类别:

  • 构造代码块。
  • 局部代码块. 大括号位于方法之内。 作用:缩短局部 变量 的生命周期,节省一点点内存。
  • 静态代码块 static
class Baby{

    int id; //身份证

    String  name;  //名字

    //构造代码块...
    {
        //System.out.println("构造代码块的代码执行了......");

    }

    //带参构造函数
    public  Baby(int i , String n){
        id  = i;
        name = n;
    }

    //无参构造方法
    public Baby(){
    }

    public void cry(){
        System.out.println(name+"哇哇哭...");
    }   
}



class Demo4 
{
    public static void main(String[] args) 
    {
        Baby b1 = new Baby(110,"狗娃");  // 狗娃 狗剩 铁蛋
        System.out.println("编号:"+ b1.id + " 名字:"+b1.name);
        /* System.out.println("编号:"+ b1.id + " 名字:"+b1.name); new Baby(112,"狗剩"); new Baby(); */
        /* new Baby(110,"狗娃"); new Baby(112,"狗剩"); new Baby(); */
    }
}

构造 代码块要注意的事项:

  • java编译器编译一个java源文件的时候,会把成员变量的声明语句提前至一个类的最前端。
  • 成员变量的初始化工作其实都在在构造函数中执行的。
  • 一旦经过java编译器编译后,那么构造代码块的代码块就会被移动构造函数中执行,是在构造函数之前执行的,构造函数的中代码是最后执行 的。
  • 成员变量的显示初始化与构造代码块 的代码是按照当前代码的顺序执行的。

this关键字 static关键字 静态函数

java中this关键字 static关键字 静态函数讲解

点这里查看

iOS中this的一些举例

static这个单词翻译成中文是“静态”的意思。关从字面上理解还真没法跟他的作用关联起来,下面我们直接先看他的作用:

  • (1)修饰局部变量

保证局部变量永远只初始化一次,在程序的运行过程中永远只有一份内存, 生命周期类似全局变量了,但是作用域不变。这句话怎么理解呢?还是以代码例子来讲解吧。

随便建一个工程,在一个控制器类上监听控制器view的点击事件方法:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{    //声明一个局部变量i
    int i = 0;    //每次点击view来到这个方法时让i自增
    i ++;    //打印结果
    NSLog(@"i=%d",i);
}
输出日志如下:

2016-10-26 14:58:48.290 fff[2760:170260] i=1
2016-10-26 14:58:49.044 fff[2760:170260] i=1
2016-10-26 14:58:49.200 fff[2760:170260] i=1....

从输出日志中我们可以看到i一直等于1,这也是预料之中的,因为每次点击进入这个方法就会重新初始化一个全新的变量i = 0,加加了一次后值变为1,然后打印出结果为1,出了这个方法后局部变量i就被释放回收。所以每次打印出来的结果都为1。

但是我们再看看局部变量i被关键字static修饰后的情况:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{    //声明一个局部变量i
  static  int i = 0;    //每次点击view来到这个方法时让i自增
    i ++;    //打印结果
    NSLog(@"i=%d",i);
}
输出日志如下:

2016-10-26 15:07:34.276 fff[2817:175155] i=1
2016-10-26 15:07:35.347 fff[2817:175155] i=2
2016-10-26 15:07:35.761 fff[2817:175155] i=3
2016-10-26 15:07:36.057 fff[2817:175155] i=4
2016-10-26 15:07:36.415 fff[2817:175155] i=5....

上面日志中可以看到i的值一直在自增。什么,它不是每次进去都被初始化赋值为0了么,怎么能累加呢。这就是关键字static修饰的局部变量的作用,让局部变量永远只初始化一次,一份内存,生命周期已经跟全局变量类似了,只是作用域不变。

  • (2)修饰全局变量

使全局变量的作用域仅限于当前文件内部,即当前文件内部才能访问该全局变量。

iOS中在一个文件声明的全局变量,工程的其他文件也是能访问的,但是我又不想让其他文件访问,这时就可以用static修饰它了,比较典型的是使用GCD一次性函数创建的单例,全局变量基本上都会用static修饰。

下面是一个GCD一次函数创建的单利

@implementation LoginTool
//static修饰全局变量,让外界文件无法访问
static LoginTool *_sharedManager = nil;

+ (LoginTool *)sharedManager {   
   static dispatch_once_t oncePredicate;   
   dispatch_once(&oncePredicate, ^{
        _sharedManager = [[self alloc] init];
    });   
   return _sharedManager;
}
  • (3)修饰函数
    static修饰函数时,被修饰的函数被称为静态函数,使得外部文件无法访问这个函数,仅本文件可以访问。这个在oc语言开发中几乎很少用,c语言倒是能看到一些影子,所以不详细探讨。