精华内容
下载资源
问答
  • 指针常量常量指针_艾孜尔江撰

    万次阅读 2021-06-17 20:32:51
    代码如下: #include <iostream> void RefConst() { char greeting[] = "Hello world!... // non-const pointer, const data (常量指针、指向常量的指针: *p,即'指针指向的值'为const,不能修改).

    在这里插入图片描述

    代码如下:

    #include <iostream>
    
    void RefConst()
    {
    	char greeting[] = "Hello world!"; // ---- (0)
    	char* p = greeting; // non-const pointer, non-const data
    	const char* p = greeting; // non-const pointer, const data (常量指针、指向常量的指针: *p,即'指针指向的值'为const,不能修改)  ---- (1)
    	char* const p = greeting; // const pointer, non-const data (指针常量、指针修饰的常量: 指向字符的指针常数,即const指针,不能修改p指针,但可修改p指针指向的内容)
    	const char* const p = greeting; // const pointer, const data
    
    }
    
    int main() {}
    
    /*
    	(0) 如果用const定义char类型的greeting字符串,下方的 “char* p = greeting; ” 将会报错无法编译通过,∵不是常量接收;
    		而当没有用常量定义的额时候下方可以任选,可以定义新的变量并定义成常量,这意味着变量可以常量,但常量不能为变量;
    	(1) p指向greeting,而greeting不是const,可以直接通过greeting变量来修改greeting的值,但却不能通过p指针来修改;
    		const char* p 等价于 char const* p;
    */
    




    作者:艾孜尔江·艾尔斯兰

    展开全文
  • 写在前面:博主是一位普普通通的19届二本大学生,平时最大的爱好就是听听歌,逛逛B站。博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的...常量池与Class常量池 2.运.

    写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站。博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事,做自己以后不会留有遗憾的事,做自己觉得有意义的事,不浪费这大好的青春年华。博主写博客目的是记录所学到的知识并方便自己复习,在记录知识的同时获得部分浏览量,得到更多人的认可,满足小小的成就感,同时在写博客的途中结交更多志同道合的朋友,让自己在技术的路上并不孤单。>本篇博客由于比较深入的写进JVM底层,所以如果有错误希望可以指出咱们共同讨论

    痛苦对我们来说,究竟意味着什么?司马迁在《报任安书》中一语道破,文王拘而演《周易》,仲尼厄而作《春秋》,屈原放逐乃赋《离骚》,左丘失明厥有《国语》。

    目录:
    1.常量池与Class常量池
    2.运行时常量池
           
    运行时常量池的简介
           
    方法区的Class文件信息,Class常量池和运行时常量池的三者关系
    3.字符串常量池
           
    字符串常量池的简介
           
    采用字面值的方式创建字符串对象
           
    采用new关键字新建一个字符串对象
           
    字符串池的优缺点
    4.字符串常量池和运行时常量池之间的藕断丝连
           
    常量池和字符串常量池的版本变化
           
    String.intern在JDK6和JDK7之后的区别(重难点)
           
    字符串常量池里存放的是引用还是字面量

    在这里插入图片描述

    1.常量池

    常量池,也叫 Class 常量池(常量池==Class常量池)。Java文件被编译成 Class文件,Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项就是常量池,常量池是当Class文件被Java虚拟机加载进来后存放在方法区 各种字面量 (Literal)和 符号引用

    在Class文件结构中,最头的4个字节用于 存储魔数 (Magic Number),用于确定一个文件是否能被JVM接受,再接着4个字节用于 存储版本号,前2个字节存储次版本号,后2个存储主版本号,再接着是用于存放常量的常量池常量池主要用于存放两大类常量:字面量和符号引用量,字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念。如下

    在这里插入图片描述

    在这里插入图片描述

    2.运行时常量池

    2.1运行时常量池的简介

    运行时常量池是方法区的一部分。运行时常量池是当Class文件被加载到内存后,Java虚拟机会 将Class文件常量池里的内容转移到运行时常量池里(运行时常量池也是每个类都有一个)。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中

    2.2方法区的Class文件信息,Class常量池和运行时常量池的三者关系

    在这里插入图片描述

    字符串常量池

    3.1字符串常量池的简介

    字符串常量池又称为:字符串池,全局字符串池,英文也叫String Pool。 在工作中,String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是我们今天要讨论的核心:字符串常量池。字符串常量池由String类私有的维护

    我们理清几个概念:

    在JDK7之前字符串常量池是在永久代里边的,但是在JDK7之后,把字符串常量池分进了堆里边。看下面两张图:

    在这里插入图片描述

    在堆中的字符串常量池: **堆里边的字符串常量池存放的是字符串的引用或者字符串(两者都有)**下面例子会有具体的讲解

    在这里插入图片描述

    符号引用表会在下面讲

    我们知道,在Java中有两种创建字符串对象的方式:

    1. 采用字面值的方式赋值
    2. 采用new关键字新建一个字符串对象。这两种方式在性能和内存占用方面存在着差别。

    3.2采用字面值的方式创建字符串对象

    package Oneday;
    public class a {
        public static void main(String[] args) {
            String str1="aaa";
            String str2="aaa";
            System.out.println(str1==str2);   
        }
    }
    运行结果:
    true
    

    采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"aaa"这个对象,如果不存在,则在字符串池中创建"aaa"这个对象,然后将池中"aaa"这个对象的引用地址返回给字符串常量str,这样str会指向池中"aaa"这个字符串对象;如果存在,则不创建任何对象,直接将池中"aaa"这个对象的地址返回,赋给字符串常量。

    对于上述的例子:这是因为,创建字符串对象str2时,字符串池中已经存在"aaa"这个对象,直接把对象"aaa"的引用地址返回给str2,这样str2指向了池中"aaa"这个对象,也就是说str1和str2指向了同一个对象,因此语句System.out.println(str1== str2)输出:true

    3.3采用new关键字新建一个字符串对象

    package Oneday;
    public class a {
        public static void main(String[] args) {
            String str1=new String("aaa");
            String str2=new String("aaa");
            System.out.println(str1==str2);
        }
    }
    运行结果:
    false
    

    采用new关键字新建一个字符串对象时,JVM首先在字符串常量池中查找有没有"aaa"这个字符串对象,如果有,则不在池中再去创建"aaa"这个对象了,直接在堆中创建一个"aaa"字符串对象,然后将堆中的这个"aaa"对象的地址返回赋给引用str1,这样,str1就指向了堆中创建的这个"aaa"字符串对象;如果没有,则首先在字符串常量池池中创建一个"aaa"字符串对象,然后再在堆中创建一个"aaa"字符串对象,然后将堆中这个"aaa"字符串对象的地址返回赋给str1引用,这样,str1指向了堆中创建的这个"aaa"字符串对象。

    对于上述的例子:
    因为,采用new关键字创建对象时,每次new出来的都是一个新的对象,也即是说引用str1和str2指向的是两个不同的对象,因此语句
    System.out.println(str1 == str2)输出:false

    字符串池的实现有一个前提条件:String对象是不可变的。因为这样可以保证多个引用可以同时指向字符串池中的同一个对象。如果字符串是可变的,那么一个引用操作改变了对象的值,对其他引用会有影响,这样显然是不合理的。

    3.4字符串池的优缺点

    字符串池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。

    4字符串常量池和运行时常量池之间的藕断丝连

    博主为啥要把他俩放在一起讲呢,主要是随着JDK的改朝换代,字符串常量池有很大的变动,和运行时常量池有关。而且网上众说纷纭,我真的在看的时候ctm了,所以博主花很长时间把这一块讲明白,如果有错误或者异议可以通知博主。博主一定会在第一时间参与讨论

    在这里插入图片描述

    4.1常量池和字符串常量池的版本变化

    • 在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代
    • 在JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说 字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
    • 在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)

    4.2String.intern在JDK6和JDK7之后的区别(重点)

    JDK6和JDK7中该方法的功能是一致的,不同的是常量池位置的改变(JDK7将常量池放在了堆空间中),下面会具体说明。intern的方法返回字符串对象的规范表示形式。其中它做的事情是:首先去判断该字符串是否在常量池中存在,如果存在返回常量池中的字符串,如果在字符串常量池中不存在,先在字符串常量池中添加该字符串,然后返回引用地址

    例子1:

    String s1 = new String("1");
    s1.intern();
    String s2 = "1";
    System.out.println(s1 == s2);
    
    运行结果:
    JDK6运行结果:false
    JDK7运行结果:false
    

    我们首先看一张图:

    在这里插入图片描述上边例子中s1是new出来对象存放的位置的引用,s2是存放在字符串常量池的字符串的引用,所以两者不同

    例子2:

    String s1 = new String("1");
    System.out.println(s1.intern() == s1);
    
    运行结果:
    JDK6运行结果:false
    JDK7运行结果:false
    

    上边例子中s1是new出来对象存放的位置的引用,s1.intern()返回的是字符串常量池里字符串的引用

    例子3:

    String s1 = new String("1") + new String("1");
    s1.intern();
    String s2 = "11";
    System.out.println(s1 == s2);
    
    运行结果:
    JDK6运行结果:false
    JDK7运行结果:true
    

    JDK6中,s1.intern()运行时,首先去常量池查找,发现没有该常量,则在常量池中开辟空间存储"11",返回常量池中的值(注意这里也没有使用该返回值),第三行中,s2直接指向常量池里边的字符串,所以s1和s2不相等。有可能会有小伙伴问为啥s1.intern()发现没有该常量呢,那是因为:

    String s1 = new String(“1”) + new String(“1”);这行代码实际操作是,创建了一个StringBuilder对象,然后一路append,最后toString,而toString其实是又重新new了一个String对象,然后把对象给s1,此时并没有在字符串常量池中添加常量

    JDK7中,由于字符串常量池在堆空间中,所以在s1.intern()运行时,发现字符串 常量池没有常量,则添加堆中“11”对象的引用到字符串常量池,这个引用返回堆空间“11”地址(注意这里也没有使用该返回值),这时s2通过查找字符串常量池中的常量,查到的是s1.intern()存在字符串常量池里的“11”对象的引用,既然都是指向堆上的“11”对象,所以s1和s2相等。

    例子4:

    String s1 = new String("1") + new String("1");
    System.out.println(s1.intern() == s1);
    

    JDK6中,常量池在永久代中,s1.intern()去常量池中查找"11",发现没有该常量,则在常量池中开辟空间存储"11",返回常量池中的值,s1指向堆空间地址,所以二者不相等。

    JDK7中,常量池在堆空间,s1.intern()去常量池中查找"11",发现没有该常量,则在字符串常量池中开辟空间,指向堆空间地址,则返回字符串常量池指向的堆空间地址,s1也是堆空间地址,所以二者相等。

    另外美团的团队写了一篇关于intern()的博客,我觉得很好可以参考一下
    深入解析String#intern

    4.3字符串常量池里存放的是引用还是字面量

    我在例子3中讲了在JDK7中字符串常量池在堆上,仔细看看例3啥时候会放引用

    那么啥时候会放字面量在字符串常量池呢,那就是在我们new一个String对象的时候如果字符串常量池里边有字面量那么就不会放,如果字符串常量池没有就会放字面量。看一个例子:

    package Oneday;
    import java.util.HashSet;
    import java.util.Set;
    public class a {
        public static void main(String[] args) {
            String str1= new String("123");
            String str2=new String("123");
            System.out.println(str1==str2);
            System.out.println(str1.intern()==str2.intern());    
        }
    }
    

    运行结果:
    在这里插入图片描述
    首先 String str1= new String("123");会在堆中创建一个对象,返回这个对象的引用给str1,同时它还会在字符串常量池中检查有没有有没有123这个对象,如果没有就==再创建一个对象(也就是123这个字面量)==在字符串常量池中

    注意这里是创建了两个对象

    但是当我们字符串常量池里边有123这个对象,那么就不用继续创建了

    上面例子的false那是因为堆中的123对象不是同一个对象,但是第二个str1.intern和s2.intern指的都是字符串常量池里的123对象所以是true

    展开全文
  • 主要介绍了C++常量详解二(常量形参,常量返回值,常量成员函数),需要的朋友可以参考下
  • 主要介绍了thinkPHP3.x常量,整理总结了thinkPHP3.x常用的各类常量,包括预定义常量、路径常量及系统常量,需要的朋友可以参考下
  • 指针常量常量指针

    万次阅读 多人点赞 2018-08-22 10:53:04
    1、指针常量——指针类型的常量(int *const p) 本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时...

    1、指针常量——指针类型的常量(int *const p)

    本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时必须初始化。用法如下:

    int a = 10, b = 20;
    int * const p = &a;
    *p = 30; // p指向的地址是一定的,但其内容可以修改

    2、常量指针——指向“常量”的指针(const int *p, int const *p)

    常量指针本质上是一个指针,常量表示指针指向的内容,说明该指针指向一个“常量”。在常量指针中,指针指向的内容是不可改变的,指针看起来好像指向了一个常量。用法如下:

    int a = 10, b = 20;
    const int *p = &a;
    p = &b; // 指针可以指向其他地址,但是内容不可以改变

    3、例题

    (1)

    int main() {
        int m = 10;
        const int n = 20; // 必须在定义的同时初始化
    
        const int *ptr1 = &m; // 指针指向的内容不可改变
        int * const ptr2 = &m; // 指针不可以指向其他的地方
    
        ptr1 = &n; // 正确
        ptr2 = &n; // 错误,ptr2不能指向其他地方
    
        *ptr1 = 3; // 错误,ptr1不能改变指针内容
        *ptr2 = 4; // 正确
    
        int *ptr3 = &n; // 错误,常量地址不能初始化普通指针吗,常量地址只能赋值给常量指针
        const int * ptr4 = &n; // 正确,常量地址初始化常量指针
    
        int * const ptr5; // 错误,指针常量定义时必须初始化
        ptr5 = &m; // 错误,指针常量不能在定义后赋值
    
        const int * const ptr6 = &m; // 指向“常量”的指针常量,具有常量指针和指针常量的特点,指针内容不能改变,也不能指向其他地方,定义同时要进行初始化
        *ptr6 = 5; // 错误,不能改变指针内容
        ptr6 = &n; // 错误,不能指向其他地方
    
        const int * ptr7; // 正确
        ptr7 = &m; // 正确
    
        int * const ptr8 = &n;
        *ptr8 = 8;
    
        return 0;
    }

    (2)判断下面程序对错,并说明理由

    int main()
    {
        char * const str = "apple";
        * str = "orange";
        cout << str << endl;
        getchar();
    }

    错误

    "apple"是字符串常量放在常量区,str指向"apple",那么str指向的是字符串常量"apple"的首地址,也就是字符a的地址,因此str指向字符a,*str就等于字符a,对*str的修改就是对字符串首字符a的修改,但"apple"是一个字符串常量,常量的值不可修改。

    根据字符串赋值规则,可以修改整个字符串,方法是对指向字符串的指针str进行赋值,如下:

    str = "orange";

    但依旧是错误的,在该赋值语句中,系统会在常量区一块新的空间写入字符串"orange"并返回其首地址,此时str由指向字符串常量"apple"的首地址变为指向字符串常量"orange"的首地址,str指向的地址发生了变化,但str是指针常量不能被修改,所以错误。

    如果想要程序编译通过,就不能将str声明为指针常量,否则str在初始化之后就无法修改。因此将const修饰符去掉,并修改字符串赋值语句,修改后程序如下:

    int main()
    {
        char * str = "apple";
        str = "orange";
        cout << str << endl;
        getchar();
    }

    参考《程序员面试笔记》

    展开全文
  • Swift 常量

    2021-01-06 02:47:11
    常量可以是任何的数据类型如:整型常量,浮点型常量,字符常量或字符串常量。同样也有枚举类型的常量常量类似于变量,区别在于常量的值一旦设定就不能改变,而变量的值可以随意更改。 常量声明 常量使用关键字 ...
  • java中常量以及常量

    2020-12-22 19:39:53
    1、举例说明 变量 常量 字面量  1 int a=10;  2 float b=1.234f;  3 String c="abc";  4 final long d=10L;  a,b,c为变量,d为常量 两者都是左值;10,1.234f,"abc",10L都是字面量;  2、常量池: ...
  • 总结: 1.常量数据成员,形式:const Type m_tData; 1)常量数据成员,需要在构造函数列表中给出,构造函数中可以用常量赋值,也可以实例化的时候...3.返回常量的函数,可以是常量指针,指针常量常量,形式: const
  • Delphi常量

    2021-01-08 04:11:54
    常量就是在第一次赋值后不能改变其值的量. Delphi有两种常量: 直接常量, 声明常量. 1直接常量:数值123 ,字符串’csdn.net’, 十六进制数$12,FALSE 和TRUE 2声明常量: 符号常量, 资源字符串, 类型常量, 数组常量 2.1...
  • JAVA常量

    2021-01-07 09:32:47
    一、常量 (一)定义 常量值又称为字面常量,它是通过数据直接表示的,因此有很多种数据类型,像整型和字符串型等。下面一一介绍这些常量值。 (二)分类 《1》整型常量值 Java 的整型常量值主要有如下 3 种形式。 ...
  • 对比变量(variable)用于存储可变的数据,常量(constant)用于存储固定不变的数据,比如: "hello" 3.14 true 与变量声明类似,声明变量用关键词var,声明常量用关键词const 在变量声明各种形式的基础上,将var...

    视频: https://www.bilibili.com/video/BV16p4y1n7tQ/

    什么是常量

    对比变量(variable)用于存储可变的数据常量(constant)用于存储固定不变的数据,比如:

    "hello"
    3.14
    true
    

    与变量声明类似,声明变量用关键词var,声明常量用关键词const

    在变量声明各种形式的基础上,将var关键词换成const关键词,即可声明常量:

    在Golang中,有两种常量,分别是:

    • 未定类常量(Untyped Constant)
    • 定类常量(Typed Constant)

    下面一一介绍~

    未定类常量

    声明时未提供类型的常量就是未定类常量(Untyped Constant),比如:

    未定类常量具有弹性(flexibility),在可兼容的类型之间转换无需显式转换

    如果把const换成var将会报错:

    math内置包里,声明了一组未定类常量:

    定类常量

    声明时提供类型的常量就是定类常量(Typed Constant),比如:

    不同于未定类常量,定类常量在转换时必须显式转换,否则将会报错

    上面的例子显示,不能将float64的定类常量pi赋值给float32的变量

    常量与变量的不同点

    • 常量声明时必须赋值:

    • 常量不能重新赋值,因为常量的值是固定不变的(fixed):

    • 已声明的常量可以不使用,不同于变量一旦声明必须使用:

    • 短声明语法不能用来声明常量:

    • 常量的数据类型只能是基本数据类型的其中一种:
      • bool
      • string
      • int家族
      • float家族
      • complex家族

    后面会学到一些类型(比如数组)不能声明为常量,但是如果有新类型是基于基本数据类型的也可以定义为常量:

    声明一组常量的语法

    定义一组常量非常简单,在math包里已经见过类似的例子:

    其中a是未定类的布尔常量,其余都是定类常量,而且我们注意到b==cd==e,上面的例子可以简化成:

    c和e都是定类常量,它们与上一行常量类型及数据保持一致

    在定义常量组时,如果不提供初始值,则表示将使用上行的表达式,不妨试试:

    总结

    next time~ :D

    原文地址: https://nbody1996.gitee.io/becoming_gopher/posts/008/

    展开全文
  • 常量池怎么理解,常量池怎么理解,常量池怎么理解!常量池怎么理解,常量池怎么理解,常量池怎么理解,
  • 主要介绍了C++常量详解一(常量指针与常量引用的初始化),需要的朋友可以参考下
  • Java常量

    千次阅读 多人点赞 2019-09-29 00:09:34
    常量值定义:常量常量值是不同的概念,常量值又称为字面常量,它是通过数据直接表示的。 关系:常量值是常量的具体和直观的表现形式,常量是形式化的表现。通常在程序中既可以直接使用常量值,也可以使用常量。 ...
  • 主要介绍了PHP中类型转换 ,常量,系统常量,魔术常量的详解的相关资料,希望通过本文能帮助到大家,让大家掌握这部分内容,需要的朋友可以参考下
  • 常量指针和指针常量常量指针常量 **常量指针:**指向常量的指针。 示例一: int n = 10; const int *p = &amp;amp;n; 此时不能通过指针修改数据对象的值,但可以改变指针的指向。比如此时指针p不能改变n的值...
  • 学习java需要深刻理解常量池吗?学习java需要深刻理解常量池吗?学习java需要深刻理解常量池吗?
  • PHP常量是一个简单值的标识符(名字)。如同其名称所暗示的,在脚本执行期间该值不能改变(除了所谓的魔术常量,它们其实不是常量
  • 在这篇文章中,我们将解释常量指针,指针常量,const pointer to const(ps:楼主以为这可以翻译成指向常量常量指针)的区别 常量指针 让我们先来理解什么是常量指针。常量指针是指指针指向的地址是常量。换句话说...
  • 常量与符号常量

    千次阅读 2019-04-16 20:53:05
    通过“数学中的变量与常量”章节的介绍,我们知道了常量的定义,就是其数据不可以修改的量。例如100这个数值,它的数值就是100,不可以改变,所以,称为常量,可以称为:常量100。 那么,在C语言中定义的数据包括有...
  • 常量指针是指–指向常量的指针,顾名思义,就是指针指向的是常量,即,它不能指向变量,它指向的内容不能被改变,不能通过指针来修改它指向的内容,但是指针自身不是常量,它自身的值可以改变,从而指向另一个常量。...
  • 指针常量 常量指针

    千次阅读 2017-08-25 11:33:31
    指针常量(指向常量的指针): const int *pa; int const *pa; 两者等价。因为指向常量的指针有时候会指向常量,所以它具有这个性质:“不能靠解引用改变它指向的对象的值”,以此保护它所指向的常量常量性。 ...
  • 这几天在看Java虚拟机方面的知识时,看到了有几种不同常量池的说法,然后我就去CSDN、博客园等上找资料,里面说的内容真是百花齐放,各自争艳,因此,我好好整理了一下,将我自认为对的理解写下来与大家共同探讨: ...
  • 指针常量就是指针本身是常量,换句话说,就是指针里面所存储的内容(内存地址)是常量,不能改变。但是,内存地址所对应的内容是可以通过指针改变的。 常量指针就是指向常量的指针,换句话说,就是指针指向的是常量...
  • 其实对于指针常量常量指针、常量指针常量这三个专用名词应经基础很久了,不过总是过一段时间就忘了或者把这三个给记混淆了。今天又遇到了这个问题,于是就想好好研究下这三个名词,以便于加深印象。  先看下: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,122,864
精华内容 449,145
关键字:

常量