java基础语法

1、注解

85dd0b51dda943c7a7b4934e099e60cb.png

137fa13ea21644a48880df8a5de3038f.png

a7cc63c89bb44d82bc358b403a185aef.png

注意:如果注解类中除了value类型的注解外还有其他类型的注解,且注解没有default默认值时,在使用注解时,需要明确写明value=“...”等。

8d21dbd5480a4bbaae03b424e6c26d76.png

08b9f838017c4c9da5fd9a5ca2d433f8.png

dca1d247b8124c99b9d30c2252f27c9e.png

ed1fd9a5e982488fa6d7febef949fbbf.png

c2570fda95424fb28bc7931984f710f7.png

import javax.annotation.Resource;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest4 {
    String value();
    double aaa() default 100;
    String [] bbb();
}
/**
 * className Demo
 *
 * @Author yrx
 * @Description //TODO
 */
@MyTest4(value = "nihao",bbb="weiguang")
public class Demo {
    @MyTest4(value = "nice",aaa = 99.8,bbb="see you")
    public void test(){
        System.out.println("true = " + true);
    }
}
import org.junit.Test;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * className AnnotationTest4
 *
 * @Author yrx
 * @Description //TODO
 */
public class AnnotationTest4 {
    @Test
    public void parseClass(){
        //1、先得到class对象
      Class c=Demo.class;
      //2、解析类上的注解
        //判断类上是否包含了某个注解
        if (c.isAnnotationPresent(MyTest4.class)) {
            MyTest4 myTest4=(MyTest4)c.getDeclaredAnnotation(MyTest4.class);

            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
        }
    @Test
    public void parseMethod() throws NoSuchMethodException {
        //1、先得到class对象
        Class c=Demo.class;
        Method m=c.getDeclaredMethod("test");
        //2、解析方法上的注解
        //判断方法对象上是否包含了某个注解
        if (m.isAnnotationPresent(MyTest4.class)) {
            MyTest4 myTest4=(MyTest4)m.getDeclaredAnnotation(MyTest4.class);

            System.out.println(myTest4.value());
            System.out.println(myTest4.aaa());
            System.out.println(Arrays.toString(myTest4.bbb()));
        }
    }
    }

bb5eef938c4b46bdbe6933ce7e411c20.png

86ca97be55e34c4aa91953f3f0d56d84.png

c6f295ef1e154bc3b48a3d1c500ee8f2.png

2、字符型常量和字符串常量

(1)字符型常量和字符串常量的区别

1. 形式:字符型常量是单引号(' ')引起的一个字符,字符串常量是多引号(" ")引起的0个或若干个字符。

2. 含义:字符常量相当于一个整型值(ASCII值),可以参加表达式的运算;字符串常量代表一个地址值(该字符串在内存中存放的位置)。

3. 占内存大小:字符常量只占2个字节,字符串常量占若干个字节。
                        
原文链接:https://blog.csdn.net/clf911423/article/details/123914066

(2)Java之String常量池

常见面试题:

​ 分析下面代码的输出结果。

public static void main(String[] args) {
    String s1 = "Hello";  
    String s2 = "Hello";  
    System.out.println(s1 == s2);  // ?

   	String s3 = new String("Hello");
    String s4 = new String("Hello");

    System.out.println(s3 == s4);  // ?
    System.out.println(s1 == s3);  // ?
}

//程序输出
true
false
false

面试题分析

创建字符串对象,和其他对象一样,会占用计算机的资源(时间、空间)。大量且频繁的创建字符串对象,会极大地影响程序的性能。

JVM为了提高性能、减少内存开销,开辟了一个字符串常量池(类似缓存区)。

String常量池:

在Java中,String常量池是一块特殊的内存区域,用于存储字符串常量。String常量池的设计目的是为了节省内存和提高性能。

当我们创建字符串常量时,如果字符串常量池中已经存在相同内容的字符串,那么新创建的字符串常量会直接引用已存在的字符串对象,而不会创建新的对象。这样可以避免重复创建相同内容的字符串,节省内存空间。

在JDK8及之后的版本中,字符串常量池的位置与其他对象的存储位置,都位于堆内存中。这样做的好处是,字符串常量池的大小可以根据需要进行调整,并且可以享受到垃圾回收器对堆内存的优化。

Java将字符串放入String常量池的方式:

直接赋值:通过直接赋值方式创建的字符串常量会被放入常量池中。

例如:String str = "Hello";

调用String类提供intern()方法:可以将字符串对象放入常量池中,并返回常量池中的引用。

例如:String str = new String("World").intern();

注意:通过new关键字创建的字符串对象不会放入常量池中,而是在堆内存中创建一个新的对象。只有通过直接赋值或调用intern()方法才能将字符串放入常量池中。

案例1:

package com.briup.chap07.test;

public class Test062_String {
	public static void main(String[] args) {
		String s1 = "Hello";  // 字符串常量,放入常量池
        String s2 = "Hello";  // 直接引用常量池中的字符串对象
        System.out.println(s1 == s2);  // true,引用相同
        
        // 直接new String对象,不会将'World'放入常量池
        String s3 = new String("World");
        
		// 调用intern()方法,将'World'放入常量池,并返回常量池中的引用
		String s4 = new java.lang.String("World").intern();
		
		String s5 = "World";
        
        System.out.println(s3 == s4);  // false,引用不同
        System.out.println(s4 == s5);  // true,引用相同
	}
}

对应内存图:

8ff364ec48614b41ba2235169d3b0895.png

package com.briup.chap07.test;

public class Test062_String2 {
    public static void main(String[] args) {
        String s1 = "a";
        String s2 = "b";

        // 常量优化机制:"a" 和 "b"都是字面值常量,借助 + 连接,其结果 "ab" 也被当作常量
        String s3 = "a" + "b";
        String s4 = "ab";

        System.out.println(s3.equals(s4));	// true
        System.out.println(s3 == s4);		// true

        System.out.println("-------------");

        String s5 = s1 + s2;
        System.out.println(s4.equals(s5));	// true
        System.out.println(s4 == s5);		// false

        System.out.println("-------------");

        String s6 = (s1 + s2).intern();
        System.out.println(s4.equals(s6));	// true
        System.out.println(s4 == s6);		// true
    }
}

注意事项:

​ 使用 + 拼接多个字符串常量,拼接的结果仍旧是字符串常量

​ 如果结果字符串常量在常量池中不存在,则Java会将其放入到字符串常量池中

//final修饰的也是常量
public static void main(String[] args) {
    String str = "ab";

    String s1 = "a";
    // String msg = new String("a"+"b");
    String msg = s1 + "b";
    System.out.println(msg == str);     //false

    //如果final修饰的变量参与运算,等同于字面值常量
    final String s2 = "a";
    // String msg2 = "a" + "b";
    String msg2 = s2 + "b";

    System.out.println(msg2 == str);    //true
}

3、java中的栈、堆、方法区

f0f8efc767a046f3beda3d6ba1e26c1c.png

栈(stack)
Java栈与堆不同每一个线程都有一个stack,栈的区域非常小,大概只有1M左右,但是存储速度非常快,所以我们把快速执行的任务存储在stack。

特点:自动分配,连续空间,先进后出原则。

1、基本数据类型(一共有八种:char、byte、short、int、long、float、double、boolean)直接分配在栈空间。

2、引用数据类型直接分配在栈空间,例如

int[] nums = new int[10];
这个nums就是对象的引用,JVM在栈空间分配了一个地址空间给nums,栈空间中的地址引用指向了堆空间中的对象。

3、方法的形式参数也直接分配在栈空间。

4、局部变量(在方法中定义,随着方法调用而存在,随着方法调用完毕而销毁,没有初始化的值,使用前必须定义和赋值)直接分配在栈空间,当局部变量所在方法执行完成之后该空间便立刻被JVM回收。

堆(heap)
在JVM中只有一个堆,在虚拟机开启时创建,所有的线程都共用这一个堆。

特点:是不连续,而且是被所有线程共享的内存区域。

1、存储创建new出来的对象,每个对象都包含一个与之对应的class的信息,而new对象的引用地址会储存在stack栈中。

2、存储数组。

方法区(method)
方法区(method)又叫静态区,

特点:方法区与堆一样是被所有线程共享的内存区域,方法区包含的都是整个程序中永远唯一的元素。

1、这里主要存储的就是类(class)、静态方法、静态变量、常量以及成员方法,还有我们常说的常量池也是方法区的一部分。
                        
原文链接:https://blog.csdn.net/NakajimaFN/article/details/125916509

4、标识符和关键字的区别

1. 什么是标识符和关键字?
标识符:在编程语言中,标识符是用来表示变量、函数、类等命名实体的名称。它由一系列字符组成,可以包含字母、数字和下划线,并且必须以字母或下划线开头。例如,在 Java 中,myVariable就是一个标识符。

关键字:关键字是编程语言中预定义的具有特殊意义的单词。这些单词被保留,不能用作标识符来命名变量、函数或类等。关键字通常用于控制程序的结构、定义数据类型、声明变量等。例如,在 Java 中,if、for、class等都是关键字。

标识符:

用于命名变量、方法、类、接口等。
可以由字母、数字、下划线 _ 和美元符号 $ 组成。
不能以数字开头,大小写敏感,没有长度限制。
例如:myVariable, sum, _count, $amount
关键字:

是Java语言预定义的具有特殊含义的单词。
不能用作标识符。
全部为小写。
例如:class, public, static, if, else

2. 标识符和关键字的区别
含义不同:标识符是用来给变量、函数、类等命名的,而关键字是编程语言中预定义的具有特殊意义的单词。

使用方式不同:标识符可以根据需要自由选择,但要遵循一定的命名规则;而关键字是编程语言中固定的,不能用作标识符。

数量不同:每个编程语言中的关键字数量是固定的,而标识符的数量取决于程序员的需求。

作用范围不同:标识符只在特定的上下文中起作用,例如变量名只在其所属的代码块内有效;而关键字具有全局性质,在整个程序中都有特殊含义。

3. 标识符和关键字的使用示例
以下是一个 Java 程序中的标识符和关键字的使用示例:

public class MyClass {
    public static void main(String[] args) {
        int myVariable = 10; // 标识符
        if (myVariable > 5) { // 关键字
            System.out.println("Hello, World!");
        }
    }
}

   

在上面的示例中,myVariable是一个标识符,用来表示一个整数类型的变量。if是一个关键字,用于控制程序的流程。

4. 标识符和关键字的优点
标识符:

可以根据需要自由选择命名,使代码更易读、理解和维护。
提高了代码的可重用性,可以在不同的上下文中使用相同的标识符。

关键字:

确保编程语言的语法规则得到正确应用,避免出现语法错误。
提供了一种统一的方式来定义数据类型、控制程序结构等,使代码更加规范化。

5. 标识符和关键字的缺点
标识符:

如果命名不规范,可能导致代码可读性差、易混淆。
过多或过长的标识符可能增加代码的复杂度。

关键字:

关键字是固定的,不能用作标识符,有时会限制了程序员的自由度。
不同编程语言中的关键字可能存在差异,需要熟悉具体语言的关键字列表。

6. 标识符和关键字的使用注意事项
标识符:

命名要遵循一定的规则,如驼峰命名法、下划线命名法等。
避免使用与关键字相同的名称作为标识符。
尽量选择有意义的名称,提高代码的可读性。

关键字:

熟悉所使用编程语言的关键字列表,避免将其作为标识符。
在编辑器中关键字通常会有特殊的颜色显示,便于辨识。
原文链接:https://blog.csdn.net/2301_78627004/article/details/134111171

default关键字

default 关键字有三种用法:

1、Switch语句中的默认分支

2、接口中的默认方法(Java 8 引入)

3、默认访问修饰符

5、自增 自减

1、“++”:自增运算符,也是一元运算符。

前置自增:变量先自增返回自增后的变量再参与运算 (先自增后运算。先己后人)。

后置自增:变量先返回原值参与运算后再自增(先参与运算,后自增 先人后己)。

原理:这里以自增为例:

后自增:

        int i = 0;
        int j = i++;

运行结果为:i=1,j=0

执行原理:

java在自增/自减时会产生一个中间变量来进行存储

j = i++;这一步会拆分成三步

			int temp = i;
			i = i + 1;
			int j = temp;

      

        int i = 0;
        int j = ++i;

运行结果为:i=1,j=1

执行原理:

j = ++i;这一步也会拆分成三步

		int i = i + 1;
		int temp = i;
		int j = temp;

6、泛型,类型擦除

源代码到字节码:泛型信息的消失

在编写含有泛型的Java源代码后,经过编译生成.class文件之后,您可能会惊讶地发现,泛型相关的信息似乎消失了。这是因为泛型信息仅在编译阶段可见,一旦编译完成,它们被擦除了,对Java虚拟机而言是不可见的。

泛型的本质是将数据类型参数化,它通过擦除的方式来实现。

擦除的工作原理

Java编译器通过以下方式来实现泛型擦除:

  • 使用Object或者边界类型来替代泛型,在生成的字节码中,只包含原始的类、接口和方法信息;
  • 在适当的位置插入强制转换代码,以确保类型安全性;
  • 对于继承了泛型类或接口的类,插入桥接方法来保留多态性。
验证擦除原理

您可以通过以下步骤验证泛型擦除的原理:

  1. 使用javac.java文件编译成.class文件;
  2. 使用反编译工具(如jad)将.class文件反编译成Java代码;
  3. 查看反编译后的Java代码,其中反映了.class文件中的信息,从而直观验证擦除原理的三个步骤。
public static <T extends Shape> void draw(T shape) { /* ... */ }

编译时,Java编译器会擦除类型参数T的具体类型信息,但它会保留T的边界信息。在这个例子中,T被声明为扩展了Shape,因此编译器会确保传入draw方法的参数是Shape的一个子类型。

然而,在生成的字节码中,类型参数T实际上不会以任何形式保留。编译器会将泛型方法处理为一个可以接受其边界类型(或边界类型的子类型)的非泛型方法。在这个例子中,draw方法会被视为一个接受Shape类型参数的方法。但是,请注意,这并不是说T被替换成了Object;而是说泛型类型参数在编译后的字节码中不再存在,取而代之的是它的边界类型(如果有的话)或Object(如果没有边界)。

由于类型擦除,您不能在运行时通过反射来确定泛型参数的具体类型。此外,泛型方法内部的类型检查(如instanceof)和类型转换在编译时会被执行,并且在必要时会插入相应的类型检查指令。

因此,虽然类型参数T在编译时会被擦除,但编译器会确保类型安全性,并且会根据需要插入必要的类型检查。在运行时,泛型方法的行为就像是一个普通的非泛型方法,只是它可以接受其泛型声明中指定的类型或其子类型的参数。

7、==和equals()

==是运算符

equals是object的方法

区别判断:看对比的是基本数据类型或者引用数据类型

equals

使用场景:用来比较引用数据类型,不能比较基本数据类型 

比较的是引用数据类型,有两种情况(一般使用到引用数据类型String会默认重写了)

        equals没有被重写,指向的就是两个对象的地址对比(一般用不到,如果强行使用就先实例化)

        equals被重写后, 比较的就是对象的值的对比(经常使用)

注释:引用数据类型和基本数据类型可以混合对比

==

比较的是基本数据类型,那么就会比较两个对象的值 

比较的是引用数据类型,那么就会比较两个对象的地址值

直白讲解使用场景:

不同数据类型进行比较用equals(因为==用不了不同数据类型对比)

宽松只对比值用:equals(因为string默认会把他们地址放一起,所以类中地址必定一样,就不用考虑地址了)

严格考虑对地址和值因素影响(具体看使用的是引用数据类型(地址)还是基本数据类型(值))对比使用:==

引用数据类型都是对比地址,基本数据类型都是对比值。equals之所以能被对比值,就是因为被重写了,经典的就是string

谨记:只要出现引用数据类型,那就是对比地址

基本概念

装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型

自动拆箱的原理

通过调用包装类型对象的xxxValue()方法将其转换为相应的基本数据类型。

自动装箱的原理

通过调用包装类型的valueOf()方法将基本数据类型转换为包装类型对象。

自动装箱和拆箱的原理是由Java编译器在编译时进行处理的,编译器会根据上下文自动插入装箱和拆箱的代码,使得程序员可以直接使用基本类型和包装类型,而不需要手动进行类型转换。这种机制可以简化代码的编写,提高代码的可读性和可维护性。此外,自动拆箱与装箱还有助于避免一些常见的编程错误,如类型不匹配等。

注意事项
1、性能损耗:自动装箱和拆箱会引入额外的性能损耗,因为需要进行对象的创建和销毁。在性能敏感的场景下,尽量避免频繁的装箱和拆箱操作。

2、空指针异常:在拆箱操作时,如果装箱对象为null,则会抛出空指针异常。因此,在进行拆箱操作之前,需要先进行null的判断。

3、对象比较:自动装箱会导致对象的创建,因此在比较两个装箱类型的值时,应使用equals()方法进行比较,而不是使用 == 运算符。因为 == 运算符比较的是对象的引用,而不是对象的值。

4、缓存对象:在装箱操作时,Java对于某些范围内的整数和字符类型进行了缓存,可以直接使用缓存对象,而不需要创建新的对象。例如,对于整数类型,范围在-128到127之间的整数会被缓存,可以直接使用Integer.valueOf()方法获取缓存对象。

5、不可变性:包装类型是不可变的,即一旦创建,其值不能被修改。如果需要修改值,需要创建一个新的包装对象。

 
    public class Test {  
        public static void main(String[] args) {      
            test();  
        }  
    
        public static void test() {  
            int i = 40;  
            int i0 = 40;  
            Integer i1 = 40;  
            Integer i2 = 40;  
            Integer i3 = 0;  
            Integer i4 = new Integer(40);  
            Integer i5 = new Integer(40);  
            Integer i6 = new Integer(0);  
            Double d1=1.0;  
            Double d2=1.0;  
              
            System.out.println("i=i0\t" + (i == i0));  
            System.out.println("i1=i2\t" + (i1 == i2));  
            System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));  
            System.out.println("i4=i5\t" + (i4 == i5));  
            System.out.println("i4=i5+i6\t" + (i4 == i5 + i6));      
            System.out.println("d1=d2\t" + (d1==d2));   
              
            System.out.println();          
        }  
    } 

    //1、这个没解释的就是true
    System.out.println("i=i0\t" + (i == i0));  //true
    //2、int值只要在-128和127之间的自动装箱对象都从缓存中获取的,所以为true
    System.out.println("i1=i2\t" + (i1 == i2));  //true
    //3、涉及到数字的计算,就必须先拆箱成int再做加法运算,所以不管他们的值是否在-128和127之间,只要数字一样就为true
    System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));//true  
    //比较的是对象内存地址,所以为false
    System.out.println("i4=i5\t" + (i4 == i5));  //false
    //5、同第3条解释,拆箱做加法运算,对比的是数字,所以为true
    System.out.println("i4=i5+i6\t" + (i4 == i5 + i6));//true      
    //double的装箱操作没有使用缓存,每次都是new Double,所以false
    System.out.println("d1=d2\t" + (d1==d2));//false

 
    public static Integer valueOf(int i) {
        //判断i是否在-128和127之间,存在则从IntegerCache中获取包装类的实例,否则new一个新实例
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
 
 
    //使用亨元模式,来减少对象的创建(亨元设计模式大家有必要了解一下,我认为是最简单的设计模式,也许大家经常在项目中使用,不知道他的名字而已)
    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
 
        //静态方法,类加载的时候进行初始化cache[],静态变量存放在常量池中
        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;
 
            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
 
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
 
        private IntegerCache() {}
    }
public  static  Integer valueOf( int  i) {
     if (i >= - 128  && i <= IntegerCache.high)   // 没有设置的话,IngegerCache.high 默认是127
         return  IntegerCache.cache[i +  128 ];
     else
         return  new  Integer(i);
}
    //boolean原生类型自动装箱成Boolean
    public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
 
    //byte原生类型自动装箱成Byte
    public static Byte valueOf(byte b) {
        final int offset = 128;
        return ByteCache.cache[(int)b + offset];
    }
 
    //byte原生类型自动装箱成Byte
    public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }
 
    //char原生类型自动装箱成Character
    public static Character valueOf(char c) {
        if (c <= 127) { // must cache
            return CharacterCache.cache[(int)c];
        }
        return new Character(c);
    }
    
    //int原生类型自动装箱成Integer
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
 
    //int原生类型自动装箱成Long
    public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }
 
    //double原生类型自动装箱成Double
    public static Double valueOf(double d) {
        return new Double(d);
    }
 
    //float原生类型自动装箱成Float
    public static Float valueOf(float f) {
        return new Float(f);
    }

首先判断i值是否在-128和127之间,如果在-128和127之间则直接从IntegerCache.cache缓存中获取指定数字的包装类;不存在则new出一个新的包装类。
    IntegerCache内部实现了一个Integer的静态常量数组,在类加载的时候,执行static静态块进行初始化-128到127之间的Integer对象,存放到cache数组中。cache属于常量,存放在java的方法区中。

为什么要有基本数据类型封装类?

1:Java是以对象为基础的编程语言

2:在如object作为参数的方法中无法直接传入基本数据类型

3:在集合中只能存储对象

Integer

获取Integer对象的方式

Java基本数据类型与封装类的区别

1.基本数据类型是值传递,封装类是引用传递

2.基本数据类型是存放在栈中的,而封装类是存放于堆中的

3.基本数据类型初始值如:int=0,而封装类Integer=null

4.集合中添加的元素一定是封装类引用数据类型

5.声明基本数据类型不需要实例化可直接赋值,而封装类必须申请一个存储空间实例化才可赋值。

1.1.1.  8种基本类型的包装类和常量池

Java 基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean;前面 4 种包装类默认创建了数值[-128,127] 的相应类型的缓存数据,Character创建了数值在[0,127]范围的缓存数据,Boolean 直接返回True Or False。如果超出对应范围仍然会去创建新的对象。

两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。**      

1.2.  方法(函数)

1.2.1.  什么是方法的返回值?返回值在类的方法里的作用是什么?

方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结  果)。返回值的作用是接收出结果,使得它可以用于其他的操作!

1.2.2.  为什么 Java 中只有值传递?

首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量 值。 它用来描述各种程序设计语言(不只是 Java)中方法参数传递方式。

Java 程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说, 方法不能修改传递给它的任何参数变量的内容。

1. 值传递概念
方法调用时,会创建副本,传递的是值的副本。也就是说传递后就不相关了。
2. 引用传递概念
方法调用时,不会创建副本,传递的是引用。也就是说传递后对形参进行重新赋值会改变引用的指向,(传递前后)
3. Java只有值传递,没有引用传递
Java中的参数传递都是值传递
基本数据类型传递的是值的拷贝
引用数据类型传递的是地址值的拷贝(引用所指向对象的地址值)

1、静态方法可以直接使用,而实例方法必须在类实例化之后通过对象来调用。
2、在外部调用静态方法时,可以使用 类名.方法名 或者 对象名.方法名的形式。实例方法只能使用后面这种方式。
3、静态方法只允许访问静态成员。而实例方法中可以访问静态成员和实例成员。
4、静态方法中不能使用this。

一、值传递
        在值传递中,函数参数是实际值的副本。在进行函数调用时,会将实际参数的值复制一份给形式参数,所以在函数内对形式参数进行修改不会影响到实际参数的值。这意味着在函数内部对形式参数进行修改不会影响到函数外部的变量。

二、引用传递
在引用传递中,函数参数是实际参数的引用,是指向实际参数的内存地址。在函数调用时,传递给函数是实际参数的地址,索引函数内对形式参数进行修改会直接影响到实际参数的值。

三、区别
值传递会创建实参的一个副本,而引用传递则直接使用实参的地址。
在值传递中,函数内部对形式参数进行修改不会影响到实际参数的值。而在引用传递中,函数内对形式参数进行修改会影响到实际参数的值。
值传递通常适合于函数不改变实际参数的情况,引用传递适合于需要函数改变实际参数的情况。

面向对象基本概念:
   面向对象 ( Object Oriented ) 是将现实问题构建关系,然后抽象成 类 ( class ),给类定义属性和方法后,再将类实例化成 实例 ( instance ) ,通过访问实例的属性和调用方法来进行使用。简写为:OOP

 (简而言之,面向过程强调的是功能行为,以函数为最小单位,考虑怎么做。)

面向过程基本概念:
   面向过程(Procedure Oriented)是一种以过程为中心的编程思想。 这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。 与面向对象明显的不同就是封装、继承、类。简写为POP。

(简而言之,面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。)

三、面向过程和面向对象的区别和联系
面向过程(Procedural Programming)和面向对象(Object-Oriented Programming)是两种不同的编程范式,它们在思想、设计和实现方式上存在一些区别和联系。

3.1 区别
抽象级别:面向过程主要关注解决问题的步骤和过程,以函数为基本单位,强调算法和流程控制。而面向对象则更关注问题领域中的实体和对象,强调将问题划分为多个相互关联的对象,并通过对象之间的交互来解决问题。

数据和行为:面向过程将数据和行为分离,强调数据的处理和操作,而面向对象则将数据和行为封装在一个单元中,即对象,对象包含了自身的状态(数据)和行为(方法)。

可重用性和扩展性:面向对象具有良好的可重用性和扩展性,通过继承、封装和多态等机制可以更方便地创建和扩展新功能。而面向过程缺乏这样的机制,代码复用和扩展相对较为困难。

3.2 联系:
对象:面向对象的核心概念是对象,而面向过程也可以使用结构体或记录等方式表示对象的概念。无论是面向对象还是面向过程,都需要处理数据和执行操作。

封装和模块化:封装是面向对象编程的基本原则,通过将数据和方法封装在对象中,可以提高代码的可维护性和安全性。而面向过程也可以使用模块化的方式将功能划分为多个独立的函数,以实现类似的效果。

设计原则:面向对象和面向过程都依赖于良好的设计原则,如单一职责原则、开放封闭原则等。不论是哪种编程范式,良好的设计原则都有助于构建高质量的软件系统。

成员变量与局部变量的区别有哪些?

语法形式:

成员变量是定义在类中;而局部变量是在代码块或方法中的变量或参数列表

成员变量可以被public/private/static所修饰;局部变量不能被static修饰;都能被final所修饰

内存存储形式:
成员变量被static修饰它属于类,没有static修饰它属于堆内存

局部变量属于栈内存

内存的生存时间:
成员变量随着对象的创建而存在

局部变量随着方法的调用而消失

如果没有给成员变量赋值则成员变量会自动以类型的默认值赋值、局部变量不会自动赋值

初始化值不同:

成员变量有默认值,基本类型的默认值为 0,复合类型的默认值为null。(被final修饰且没有static的必须显式赋值),局部变量不会自动赋值,所以局 部变量在定义后先要赋初值,然后才能使用。

创建一个对象可以使用 new 关键字来实例化一个类。通过 new 运算符,我们可以在内存中分配空间,并调用类的构造方法来初始化对象。

对象实体和对象引用是两个不同的概念:

对象实体:指的是在内存中真正存在的对象,它占据一定的内存空间,并保存了对象的属性值。
对象引用:指的是对对象的引用或者说指针,它是一个变量,用于存储对象在内存中的地址。通过对象引用,我们可以访问和操作对象的属性和方法。
简单来说,对象实体是具体的对象,而对象引用是指向对象实体的指针。

Java–对象实体与对象引用有何不同


通过new 创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向 0 个或 1 个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有 n 个引用指向它(可以用 n 条绳子系住一个气球)。

对象的相等与指向他们的引用相等,两者有什么不同?
对象的相等,比的是内存中存放的内容是否相等。而引用相等,比较的是他们指向的内存地址是否相等。

1.构造方法的定义与说明


  构造方法 : 用来初始化对象的方法
(1)  构造方法名与类名相同 , 且没有返回值,且不需要使用void修饰 。
(2)  作用:在构造方法中为创建的对象初始化赋值,
(3)  在创建一个对象的时候,至少要调用一个构造方法。
(4) 每个类都有构造方法。如果没有显式地为类定义构造方法,Java将会为该类提供一个默认构造方法,但是只要在一个Java类中定义了一个构造方法后,默认的无参构造方法即失效。

1.构造方法的作用
在创建类对象同时,初始化类的实例对象(成员变量)

2.构造方法的特点
(1)构造方法的方法名必须与类名相同

(2)构造方法没有返回值 不用void声明

(3)用户不能直接调用构造方法,只能由new运算符调用

(4)构造方法在用户创建对象时系统自动调用执行

(5)不能在方法内部用return语句返回一个值

3.如何声明构造方法
(1)隐式声明(系统自动声明)

当类中没有构造方法的显示声明时系统自动在类体中添加一个与类名同名,不含方法体为空的构造方法,用于初始化类的实例对象。

(2)显示声明(系统提供的构造方法不能满足时使用)

格式:

修饰符 方法名 ([参数列表]){

        方法体

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值