04.类的初始化

认识类的初始化:
在初始化阶段,java虚拟机执行类的初始化语句,为类的静态变量赋予初始值。在程序中, 静态变量的初始化有两种途径:
(1)在静态变量的声明处进行初始化
(2)在静态代码块中进行初始化
在下面代码中,静态变量都被显式初始化,而静态变量c没有被显式初始化,它将保持默认值0

public class Sample{
    public static int a = 1;//在静态变量的声明处被初始化
    public static long b;
    public static long c;
    static{
        b=2;//在静态代码块中进行初始化
    }
}

静态变量的声明语句,以及静态代码块都被看做类的初始化语句,java虚拟机会按照初始化语句在类文件中的先后顺序来执行他们。例如当以下类Sample被初始化后,a的值是4

public class Sample{
    static int a = 1;
    static { a = 2; }
    static { a = 4; }
    public static void main(string args[]){
        System.out.println("a = "+ a);//打印a = 4
    }

}

类的初始化步骤:

  1. 假如这个类还没有进行加载和连接,那就先进行加载和连接。
  2. 假如类存在直接的父类,并且父类没有被初始化,那就直接先初始化父类
  3. 假如类中存在初始化语句,那就依次执行这些初始化语句

以下代码会输出:
count1 = 1
count2 = 0

package test4;
class Singleton {
    /*
     * 2.因为是初次使用Singleton这个类, 所以类里面的静态变量都要初始化默认值singleton=null ,count1=0,count2=0
     * 3.开始按顺序初始化,给变量赋值:
     * -singleton生成这个类的实例,那么就要执行这个类的构造方法Singleton() count1=1;count2=1;
     * -count1 没有给初始化的值,那他的值就不变, count1=1;
     * -count2给了一个初始化的值,那么count2=0;
     */

    private static Singleton singleton = new Singleton();
    public static int count1;
    public static int count2=0;
    private Singleton(){
        count1 ++;
        count2 ++;
    }
    public static Singleton getInstance(){
        return singleton;
    }
}

public class MyTest{
    public static void main(String[] args) {
        //1.因为使用的是Singleton中的方法, 所以得加载Sgingleton这个类;
        Singleton singleton = Singleton.getInstance();
        System.out.println("count1 = "+singleton.count1);
        System.out.println("count2 = "+singleton.count2);
    }
}



import java.util.Random;

class FinalTest {
    public static final int x = new Random().nextInt(100);
    static{
        System.out.println("Final static block");
    }
}
public class MyTest{
    public static void main(String[] args) {
        System.out.println(FinalTest.x);
    }
}

输出:
Final static block
84


class FinalTest {
    public static final int x = 6/2;
    static{
        System.out.println("Final static block");
    }
}
public class MyTest{
    public static void main(String[] args) {
        System.out.println(FinalTest.x);
    }
}

输出:3
为什么有的会输出静态代码块的内容,有的不会呢?
因为FinalTest.x 中的final x = 6/2,是编译时的常量,在使用的时候, 是不会对类初始化的,如果是非编译时的常量的话, 就会对类进行初始化。
所谓对类初始化和不对类初始化,就看类的静态代码块有没有执行。

课后测试题:

package test4;

class Parent{
    static int a = 3;
    static{
        System.out.println("parent is block");
    }
}
class Child extends Parent{
    static int b = 4;
    static{
        System.out.println("child is block");
    }
}
public class MyTest{
    static{
        //1.因为是启动类,所以会先输出
        System.out.println("main is block");
    }
    public static void main(String[] args) {
//      System.out.println(Child.b);
        Parent parent;
        //2.因为上面的parent并没有实例化,不做任何操作,输出“---”
        System.out.println("-------");
        //实例化Parent,初始化parent静态变量以及静态代码块,a=0(赋予默认值),输出“parent is block” 
        //然后初始化a,给a赋值,a=3
        parent = new Parent();
        //输出a
        System.out.println(Parent.a);
        //使用Child类,那么就得初始化child类。
        //因为parent类已经初始化过了,所以直接初始化Child类静态变量以及静态代码块,先给b赋予默认值0,输出“child is block”。然后初始化b,给b赋值4,b=4;输出b
        System.out.println(Child.b);
    }
}

package test4;

class Parent{
    static int a = 3;
    static{
        System.out.println("parent is block");
    }
    static void doSomething(){
        System.out.println("do something");
    }
}
class Child extends Parent{
    static int b = 4;
    static{
        System.out.println("child is block");
    }
}
public class MyTest{
    public static void main(String[] args) {
        System.out.println(Child.a);
        Child.doSomething();
    }
}

输出:
3
do something

发现child静态块的语句并没有输出(也就是没有初始化),不是说好调用哪个类的静态变量或者静态方法,就要初始化那个类吗?我明明掉用了Child类里面的静态变量a了呀?
哈哈,原因是我们在MyTest类里面调用的是并不是child类里面的属性, 而是他父类中的属性。所以,不会对child进行初始化的。

总结:
只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或者接口的主动使用


package test4;

class Cl{
    static{
        System.out.println("my name is cl!");
    }
}
public class MyTest{
    public static void main(String[] args) throws Exception{
        //获得系统类加载器
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        Class<?> clazz = loader.loadClass("test4.Cl");
        System.out.println("======分割=====");
        clazz = Class.forName("test4.Cl");
    }
}

输出结果:
======分割=====
my name is cl!

总结:
调用ClassLoader类的loadClass()方法加载一个类,并不是对类的主动调用,不会导致类的初始化。


当java虚拟机初始化一个类时,要求他的所有父类都已经初始化,但是这条规则,并不适用于接口
- 在初始化一个类时,并不会先初始化它所实现的接口
- 在初始化一个接口时,并不会先初始化它的父接口
因此,一个父接口并不会因为他的子接口或者实现类的初始化而初始化,只有当程序首次使用特定接口的静态变量时,才会导致接口的初始化。

<think>嗯,用户需要查找OS04A10摄像头传感器的初始化例程代码或文档。这个需求很具体,应该是嵌入式开发或摄像头驱动相关的工作场景。 从用户提问的措辞看,ta可能正在调试摄像头模块,需要参考实现。OS04A10是OmniVision的400万像素传感器,常用于安防摄像头和物联网设备。这初始化通常涉及I2C寄存器配置序列,但具体实现会因平台而异。 用户提供的引用材料里有两个关键线索:引用[2]提到三星平台总线驱动开发,引用[5]涉及设备树配置问题。这说明用户可能在ARM Linux环境下开发,平台可能是三星Exynos或似SoC。需要重点考虑平台总线驱动框架和设备树配置。 摄像头初始化通常包含三个核心部分:硬件接口配置(I2C/SPI)、传感器寄存器初始化序列、媒体控制器(v4l2)注册。引用[5]特别提醒了显示子系统状态的影响,这点很重要——即使不接屏幕,display_subsystem也必须启用才能启动视频流水线。 考虑到用户可能需要完整示例,准备提供四层结构:1)设备树节点示例,包含关键参数;2)驱动注册代码框架;3)典型初始化序列伪代码;4)v4l2操作集挂接。特别强调电源管理和时钟配置,因为这是OS04A10容易出问题的地方。 用户没有说明具体平台,所以补充了平台差异提示。Linux内核源码的drivers/media/i2c/ovti-*路径是重要参考源,但不同内核版本差异较大。最后提醒用户注意时钟频率精度要求,OS04A10对24MHz主时钟的容差很敏感。 相关问题设计成阶梯式:从基础寄存器配置到高级电源管理,再到平台移植和调试技巧。第四个问题特意加入"无图像"的故障排查,因为引用[5]的设备树案例说明这是常见痛点。</think>以下是关于OS04A10摄像头传感器初始化例程的参考信息及代码实现思路: ### 一、核心初始化流程 1. **硬件接口配置** OS04A10通常通过I2C接口控制,需在设备树中声明: ```dts &i2c1 { status = "okay"; os04a10: sensor@3c { compatible = "ovti,os04a10"; reg = <0x3c>; clocks = <&cru CLK_CIF_OUT>; reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; pwdn-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; // MIPI时钟配置 clock-names = "xvclk"; clock-frequency = <24000000>; }; }; ``` 2. **电源管理序列** 典型上电顺序: ```c // 伪代码示例 enable_power_supply(); gpio_set(reset_gpio, 0); // 复位拉低 msleep(5); gpio_set(pwdn_gpio, 1); // 退出待机 gpio_set(reset_gpio, 1); // 释放复位 msleep(20); ``` ### 二、寄存器初始化代码框架 ```c #include <linux/i2c.h> #include <media/v4l2-subdev.h> #define OS04A10_CHIP_ID_REG 0x300a #define OS04A10_CHIP_ID 0x530410 static int os04a10_init_registers(struct i2c_client *client) { u8 chip_id[2]; // 验证传感器ID i2c_read_reg(client, OS04A10_CHIP_ID_REG, chip_id, 2); if ((chip_id[0] << 8 | chip_id[1]) != OS04A10_CHIP_ID) { dev_err(&client->dev, "ID mismatch: 0x%04X\n", chip_id); return -ENODEV; } // 关键寄存器配置序列 const struct regval init_seq[] = { {0x0100, 0x00}, // 软件复位 {0x0103, 0x01}, // 退出软件待机 {0x0300, 0x04}, // PLL预分频 {0x0301, 0x00}, // PLL倍频 // ... 更多配置(分辨率/帧率等) {REG_NULL, 0x00} }; return os04a10_write_regs(client, init_seq); } ``` ### 三、V4L2集成要点 1. **媒体控制器注册** ```c static int os04a10_probe(struct i2c_client *client) { struct v4l2_subdev *sd; sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL); v4l2_i2c_subdev_init(sd, client, &os04a10_ops); media_entity_pads_init(&sd->entity, 1, &pad); sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; } ``` 2. **操作集实现** ```c static const struct v4l2_subdev_ops os04a10_ops = { .core = &os04a10_core_ops, .video = &os04a10_video_ops, .pad = &os04a10_pad_ops, }; ``` ### 四、关键注意事项 1. **时钟精度**:需确保24MHz主时钟偏差≤±10ppm(数据手册要求)[^1] 2. **启动延迟**:复位信号释放后需等待≥10ms再访问I2C 3. **MIPI配置**:需匹配接收端CSI控制器的lane数量和速率 4. **设备树状态**:如引用[5]所述,禁用`display_subsystem`会导致视频流异常 > **调试建议**:通过`i2cdetect`验证I2C地址,使用逻辑分析仪检查MIPI时钟同步信号。完整驱动可参考Linux内核源码: > `drivers/media/i2c/ovti-os04a10.c` (Linux 5.10+) --- ### 相关问题 1. OS04A10的I2C寄存器写入失败应如何排查? 2. 如何配置OS04A10输出1080P@30fps的MIPI数据流? 3. 在ARM Linux平台移植OS04A10时,设备树需要哪些关键配置? 4. OS04A10启动后图像偏色可能由哪些寄存器配置错误导致? [^1]: OS04A10数据手册要求时钟精度±10ppm [^2]: 设备树配置需匹配硬件连接(I2C地址/GPIO极性等) [^5]: 显示子系统禁用会导致视频流水线中断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值