final 有什么用?
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用地址,地址中的内容是可以改变的。
final int b=3; b=2;//将报错
static存在的主要意义
-
static的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法!
-
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
-
为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
public class user { static { System.out.println("123"); } }
public class test2 { public static void main(String[] args) { user u1=new user(); user u2=new user(); } }
控制台只会输出一次 123
在 Java 中,如何跳出当前的多重嵌套循环
- 在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环。例如:
-
public class test3 { public static void main(String[] args) { ok: for(int i=0;i<10;i++){ for(int j=0;j<10;j++){ System.out.println(j); if(j==5){ break ok; } } } } }
面向对象的特征主要有以下几个方面
-
继承:是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。
-
多态:父类引用指向子类对象,调用方法时会调用子类的实现,而不是父类的实现,这叫多态。
-
public class Animal { int a=10; static int b=20; public void eat(){ System.out.println("动物吃饭"); } public static void sleep(){ System.out.println("动物睡觉"); } public void play(){ System.out.println("动物玩游戏"); } }
public class Cat extends Animal{ int a=50; static int b=60; public void eat(){ System.out.println("猫咪吃饭"); } public static void sleep(){ System.out.println("猫咪睡觉"); } }
public class test { public static void main(String[] args) { Animal animal=new Cat(); animal.eat(); animal.play(); animal.sleep(); System.out.println(animal.a); System.out.println(animal.b); } }
猫咪吃饭 动物玩游戏 动物睡觉 10 20 变量(包括静态与非静态):编译看左运行看左 非静态方法:编译看左,运行看右边 静态方法:编译看左运行看左
如果想使用子类变量和静态方法:
-
public class test { public static void main(String[] args) { Animal animal=new Cat(); Cat cat= (Cat) animal; cat.eat(); cat.play(); cat.sleep(); System.out.println(cat.a); System.out.println(cat.b); } }
猫咪吃饭 动物玩游戏 猫咪睡觉 50 60
-
关于继承特点:
1.子类拥有父类非 private 的属性和方法。2.子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3.子类可以用自己的方式实现父类的方法。
-
封装:把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法
抽象类和接口的对比
相同点:
- 都位于继承的顶端,用于被其他实现或继承
- 都包含抽象方法,其子类都必须覆写这些抽象方法
不同点:
抽象类中抽象方法必须加abstract,接口可以省略。
成员变量与局部变量
- 成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
- 局部变量:在方法被调用,或者语句被执行的时候存在,如果是基本数据类型存储在栈内存中,如果是是对象,对象的引用存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。
- 成员变量:有默认初始值。
- 局部变量:没有默认初始值,使用前必须赋值。
构造方法
- 名字与类名相同;
- 没有返回值,但不能用void声明构造函数;
- 生成类的对象时自动执行,无需调用。
- 关于继承:Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。如果父类只有有参构造,那么子类也只能有有参构造
package test; public class test1 { int a; public test1(int a) { this.a=a; } }
package test; public class test2 extends test1{ public test2(int a) { //不实现父类有参构造将会报错 super(a); } }
静态变量和实例变量区别
- 静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份(在方法区),在类的加载过程中,JVM只为静态变量分配一次内存空间。
- 实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的(对象实例在堆内存),在内存中,创建几次对象,就有几份成员变量。
在一个静态方法内调用一个非静态成员为什么是非法的?
- 静态方法在类第一次被调用时就被加载到内存方法区中,这时就可以调用,此时类还没初始化所有静态成员还没初始化,所有调用是非法的
内部类
- 在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本身就是类的一个属性,与其他属性定义方式一致
- 内部类可以分为四种:成员内部类、局部内部类(定义在方法中的内部类)、匿名内部类和静态内部类。
-
public class Outer { private void test(final int i) { new Service() { public void method() { for (int j = 0; j < i; j++) { System.out.println("匿名内部类" ); } } }.method(); } } //匿名内部类必须继承一个类或实现一个已有的接口 interface Service{ void method(); }
- 匿名内部类必须继承一个抽象类或者实现一个接口。
- 匿名内部类不能定义任何静态成员和静态方法。
- 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
== 和 equals和hashCode (重点理解)
- == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)
-
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
-
两个对象有相同的hashcode值(hashcode方法被重写),它们也不一定是相等的
-
超类的hashCode 返回的是对象的地址
-
HashSet方法存入对象时,先比较对象的hashCode(hashcode方法被重写,例如用%3取余映射,如果映射不同则值肯定不同)是否相同,如果不同则不相等,如果相同,则调用equals(equals方法也被重写,此时比较对象中值)比较是否相等。
Java 中只有值传递
- 如果是基本数据类型,值传递不会改变其原有值
- 如果是对象,会改变原有对象
-
值传递和引用传递有什么区别
值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相关了。
引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)
-
public static void main(String[] args) { int num1 = 10; int num2 = 20; swap(num1, num2); System.out.println("num1 = " + num1); System.out.println("num2 = " + num2); } public static void swap(int a, int b) { int temp = a; a = b; b = temp; System.out.println("a = " + a); System.out.println("b = " + b); }
a = 20 b = 10 num1 = 10 num2 = 20
public static void main(String[] args) { int[] arr = { 1, 2, 3, 4, 5 }; System.out.println(arr[0]); change(arr); System.out.println(arr[0]); } public static void change(int[] array) { // 将数组的第一个元素变为0 array[0] = 0; } 1 0
反射三种实现:
public class Get {
//获取反射机制三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一(通过建立对象)
Student stu = new Student();
Class classobj1 = stu.getClass();
System.out.println(classobj1.getName());
//方式二(所在通过路径-相对路径)
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
//方式三(通过类名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName());
}
什么是字符串常量池?
- 字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。
是否可以继承 String 类
- String 类是 final 类,不可以被继承。
String str="i"与 String str=new String(“i”)一样吗?
- 不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
包装类相关
- 原始类型: boolean,char,byte,short,int,long,float,double
- 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double