答: 区别如下:
作用域 当前类 同一package 子孙类 其他package
public √ √ √ √
protected √ √ √ ×
friendly √ √ × ×
private √ × × ×
不写时默认为friendly
答: &是位运算符,表示按位与运算, &&是逻辑运算符,表示逻辑与(and)
答: Collection是集合类的上级接口,继承与他的接口主要有Set 和List.
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作
答: assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中, assertion就
是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为true;
如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。一般来说, assertion用于保证程序最
基本、关键的正确性。 assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后, assertion检查通常是
关闭的
答: 两个,一个字符对象(常量池),一个字符对象引用对象(内存)
准确来说在代码执行时只创建了一个对象,因为只new了一次
但在实际程序执行时多在常量池创建了一个“xyz”对象
==判断引用地址,equals判断值
Java为了避免产生大量的string对象,设计了一个字符串常量池
工作原理:创建一个字符串时,jvm首先检查常量池中是否有值相等的字符串,如果有,不再创建,直接返回字符串引用地址,若没有,则创建,放在常量池中,返回新创建的字符串的引用地址。所以没有new新对象,两个值相等的字符串s1和s2引用地址相同。
答: Math.round(11.5)==12;Math.round(-11.5)==-11;
round方法返回与参数最接近的长整数,参数加1/2后求其floor
有什么错? short s1 = 1; s1 += 1;有什么错答: short s1 = 1; s1 = s1 + 1; (s1+1运算结果是int型,需要强制转换类型) short s1 = 1; s1 += 1;(可以正确编译)
答: java中的保留字,现在没有在java中使用
答: 数组没有length()这个方法,有length的属性。 String有有length()
封装给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。在 Java 当中,有 4 种访问权限 对应着三个修饰符: public, private , protected。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。
下面列出了使用封装的一些好处:
①通过隐藏对象的属性来保护对象内部的状态。
②提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展。
③禁止对象之间的不良交互提高模块化。
多态是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作可以应用到其他类型的值上面。表现形式为overload和override
继承给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用行,也可以在不修 改类的情况下给现存的类添加新特性。
抽象是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节来创建类。 Java 支持创建只暴漏接口而不包含方法实现的抽象的类。这种抽象技术的主要目的 是把类的行为和实现细节分离开。
抽象和封装是互补的概念。一方面,抽象关注对象的行为。另一方面,封装关注对象行为的 细节。一般是通过隐藏对象内部状态信息做到封装,因此,封装可以看成是用来提供抽象的 一种策略。
变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。
内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。
因此,通过定义不同类型的变量,可以在内存中储存整数、小数或者字符。
Java的两大数据类型:
Java语言提供了八种基本类型。六种数字类型(四个整数型(默认是int 型),两个浮点型(默认是double 型)),一种字符类型,还有一种布尔型。
数据类型是8位、有符号的,以二进制补码表示的整数;(256个数字),占1字节
最小值是-128(-2^7);
最大值是127(2^7-1);
默认值是0;
byte类型用在大型数组中节约空间,主要代替整数,因为byte变量占用的空间只有int类型的四分之一;
例子:byte a = 100,byte b = -50。
数据类型是16位、有符号的以二进制补码表示的整数,占2字节
最小值是-32768(-2^15);
最大值是32767(2^15 - 1);
Short数据类型也可以像byte那样节省空间。一个short变量是int型变量所占空间的二分之一;
默认值是0;
例子:short s = 1000,short r = -20000。
数据类型是32位、有符号的以二进制补码表示的整数;占3字节
最小值是-2,147,483,648(-2^31);
最大值是2,147,485,647(2^31 - 1);
一般地整型变量默认为int类型;
默认值是0;
例子:int a = 100000, int b = -200000。
数据类型是64位、有符号的以二进制补码表示的整数;占4字节
最小值是-9,223,372,036,854,775,808(-2^63);
最大值是9,223,372,036,854,775,807(2^63 -1);
这种类型主要使用在需要比较大整数的系统上;
默认值是0L;
例子: long a = 100000L,int b = -200000L。
long a=111111111111111111111111(错误,整数型变量默认是int型)
long a=111111111111111111111111L(正确,强制转换)
数据类型是单精度、32位、符合IEEE 754标准的浮点数;占4字节 -3.4*E38- 3.4*E38。。。浮点数是有舍入误差的
float在储存大型浮点数组的时候可节省内存空间;
默认值是0.0f;
浮点数不能用来表示精确的值,如货币;
例子:float f1 = 234.5f。
float f=6.26(错误 浮点数默认类型是double类型)
float f=6.26F(转换正确,强制)
double d=4.55(正确)
数据类型是双精度、64位、符合IEEE 754标准的浮点数;
浮点数的默认类型为double类型;
double类型同样不能表示精确的值,如货币;
默认值是0.0d;
例子:double d1 = 123.4。
数据类型表示一位的信息;
只有两个取值:true和false;
这种类型只作为一种标志来记录true/false情况;
默认值是false;
例子:boolean one = true。
类型是一个单一的16位Unicode字符;用 ‘’表示一个字符。。java 内部使用Unicode字符集。。他有一些转义字符 ,2字节
最小值是’\u0000’(即为0);
最大值是’\uffff’(即为65,535);可以当整数来用,它的每一个字符都对应一个数字
(基本类型引用自“https://blog.csdn.net/daisylovezly/article/details/79610602”)
拓展1:float型float f=3.4是否正确?
答:不正确。精度不准确,应该用强制类型转换,如下所示: float f=(float)3.4
在JVM之中再好的算法,也敌不过一个好烂的程序员。一个程序要想写好有两点:1.按照开发标准进行 2.请写有用代码。
而对于垃圾的产生与回收的处理之中,要想进行更好的控制,就必须清楚的掌握Java中的四种引用方式。
即使进行了多次的GC回收,即使JVM真的已经不够用了,即使JVM最终不得已抛出了OOM错误,那么该引用继续抢占;
当内存空间不足时,可以回收此内存空间。如果充足则不回收,可以用其完成缓存的一些处理操作开发。
缓存:保证数据更快的操作(读取)。是不重要的数据。可以作为牺牲来释放空间。
不管内存是否紧张,只要一出现GC处理,则立即回收。
和没有引用是一样的。
比如HashMap根据key取得值,设置key值为null和不设置key值的效果是一样的。
自动拆箱和自动装箱
Java为每种基本数据类型都提供了对应的包装器类型。举个例子:
public class TestMain
{
public static void main(String[] args)
{
Integer i = 10;
}
}
这个过程中会自动根据数值创建对应的Integer对象,这就是自动装箱。再看另外一段代码:
public class TestMain
{
public static void main(String[] args)
{
Integer integer = 10;
int i = integer;
}
}
这个过程中会根据包装器类型自动将数据转换为基本类型,这就是自动拆箱。
自动装箱的时候,Java虚拟机会自动调用Integer的valueOf方法;
自动拆箱的时候,Java虚拟机会自动调用Integer的intValue方法。
这就是自动拆箱和自动装箱的原理。
提醒:小心空指针异常
public static void main(String[] args) throws Exception
{
Object obj = getObj(null);
int i = (Integer)obj;
}
public static Object getObj(Object obj)
{
return obj;
}
如果运行的话:
Exception in thread "main" java.lang.NullPointerException
at main.Test7.main(Test7.java:8)
这种使用场景很常见,我们把一个int数值放在session或者request中,取出来的时候就是一个类似上面的场景了。所以,小心自动拆箱时候的空指针异常。
拓展1
public class TestMain
{
public static void main(String[] args)
{
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
}
}
运行结果为:
true
false
public class TestMain
{
public static void main(String[] args)
{
Double d1 = 100.0;
Double d2 = 100.0;
Double d3 = 200.0;
Double d4 = 200.0;
System.out.println(d1 == d2);
System.out.println(d3 == d4);
}
}
运行结果为:
false
false
产生这样的结果的原因是
Byte、Short、Integer、Long、Char这几个装箱类的valueOf()方法是以128位分界线做了缓存的,假如是128以下且-128以上的值是会取缓存里面的引用的,以Integer为例,其valueOf(int i)的源代码为:
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
而Float、Double则不会,原因也很简单,因为byte、Short、integer、long、char在某个范围内的整数个数是有限的,但是float、double这两个浮点数却不是。
要有缓存这个概念,缓存对于提高程序运行效率、节省内存空间是有很大帮助的
当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java 编译器会为这个类创建一个默认的构造函数。
Java 中构造函数重载和方法重载很相似。可以为一个类创建多个构造函数。每一个构造函数 必须有它自己唯一的参数列表。
Java 不支持像 C++中那样的复制构造函数, 这个不同点是因为如果你不自己写构造函数的情况下, Java 不会创建默认的复制构造函数。
接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象。
抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。
所以,在高级语言上,一个类只能继承一个类(抽象类)但是可以实现多个接口
(1)接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类。
(2)接口可以多继承(不可以实现另一个接口),抽象类不行
(3)接口定义方法,不能实现(某个类实现中所有抽象方法,否则要声明为抽象类),而抽象类可以实现部分方法。
(4)接口中基本数据类型为 static 而抽类象不是的。
(5)Java 接口中声明的变量默认都是 public static final (默认)的。 抽象类可以包含非 final 的变量。
(6)Java 接口中的成员方法默认是 public abstract的。抽象类的方法可以是 private(不可以), protected 或者是 public。
(7)接口是绝对抽象的, 不可以被实例化。抽象类也不可以被实例化
(8)接口没有构造器,抽象类可以有构造器
(9)接口没有main方法,抽象类可以有
(10)接口中不能有静态代码块和静态方法,抽象类可以有
拓展1:有抽象方法的类可以成为抽象类,但抽象类不一定有抽象方法
拓展2:abstract的method不可同时是static,不可同时是native,不可同时是synchronized
拓展3:接口A有void C()方法,接口B有int C()方法,则无法同时实现这两个接口
拓展4:A是接口,B实现A,C继承B,则C也是A的子类
拓展5:父子类中有同名属性这不是错误,只是会造成歧义而已
对象被值传递,意味着传递了对象的一个副本。因此,就算是改变了对象副本,也不会影响 源对象的值。
对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对 象所做的改变
会反映到所有的对象上。
答: witch(expr1)中, expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。
long,string 都不能作用于swtich
答: 是能够定义成为一个中文的,因为java中以unicode编码,一个char占16个字节,所以放一个中文是没问题的
答: 可以。必须只有一个公共类名 且与文件名相同。
答: Clone 有缺省行为, super.clone();他负责产生正确大小的空间,并逐位复制。
break :跳出当前循环;但是如果是嵌套循环,则只能跳出当前的这一层循环,只有逐层break才能跳出所有循环;
continue:终止当前循环,但是不跳出循环(在循环中continue后面的语句是不会执行了),继续往下根据循环条件执行循环。
(1).return 从当前的方法中退出,返回到该调用的方法的语句处,继续执行。
(2).return 返回一个值给调用该方法的语句,返回值的数据类型必须与方法的声明中的返回值的类型一致。
(3). return后面也可以不带参数,不带参数就是返回空,其实主要目的就是用于想中断函数执行,返回调用函数处。
特别注意:返回值为void的方法,从某个判断中跳出,必须用return;
1、可以使用遍历数组的方式去遍历可变参数
2、可变参数是利用数组实现的
可变长度参数必须作为方法参数列表中的的最后一个参数且方法参数列表中只能有一个可变长度参数。
在编译的时候编译器会自动将对for这个关键字的使用转化为对目标的迭代器的使用
①ArrayList之所以能使用foreach循环遍历,是因为 ArrayList所有的List都是Collection的子接口,而Collection是Iterable的子接口,ArrayList的父类 AbstractList正确地实现了Iterable接口的iterator方法。之前我自己写的ArrayList用foreach循环直接报空指针 异常是因为我自己写的ArrayList并没有实现Iterable接口
②任何一个集合,无论是JDK提供的还是自己写的,只要想使用foreach循环遍历,就必须正确地实现Iterable接口
Java将对于数组的foreach循环转换为对于这个数组每一个的循环引用。
Java将对于数组的foreach循环转换为对于这个数组每内部类分为四种:成员内部类、局部内部类、匿名内部类、静态内部类。
①成员内部类是依附其外部类而存在的,如果要产生一个成员内部类,比如有一个其外部类的实例
②成员内部类中没有定义静态方法,不是例子不想写,而是成员内部类中不可以定义静态方法
③成员内部类可以声明为private的,声明为private的成员内部类对外不可见,外部不能调用私有成员内部类的public方法
④成员内部类可以声明为public的,声明为public的成员内部类对外可见,外部也可以调用共有成员内部类的public方法
⑤成员内部类可以访问其外部类的私有属性,如果成员内部类的属性和其外部类的属性重名,则以成员内部类的属性值为准
①局部内部类没有访问修饰符
②局部内部类要访问外部的变量或者对象,该变量或对象的引用必须是用final修饰的
是唯一没有构造器的类,其使用范围很有限,一般都用于继承抽象类或实现接口(注意只能继承抽象类,不能继承普通类),匿名内部类Java自动为之起名为XXX$1.classs。另外,和局部内部类一样,匿名内部类必须是用final修饰的。
①静态内部类中可以有静态方法,也可以有非静态方法
②静态内部类只能访问其外部类的静态成员与静态方法
③和普通的类一样,要访问静态内部类的静态方法,可以直接"."出来不需要一个类实例;要访问静态内部类的非静态方法,必须拿到一个静态内部类的实例对象
④注意一下实例化成员内部类和实例化静态内部类这两种不同的内部类时写法上的差别
A.成员内部类:外部类.内部类 XXX = 外部类.new 内部类();
B.静态内部类:外部类.内部类 XXX = new 外部类.内部类();
先理清楚两点:
1、匿名内部类是唯一没有构造器的类
2、局部内部类有构造器,通过构造器把外部的变量传入局部内部类再使用是完全可以的
那万一局部内部类中没有定义构造器传入局部变量怎么办呢?这时候Java想了一个办法,把局部变量修饰为final就好了,被final修饰的变量相当于是一个常量,编译时就可以确定并放入常量池。这样即使匿名内部类没有构造器、局部内部类没有定义有参构造器,也无所谓,反正要用到的变量编译时候就已经确定了,到时候去常量池里面拿一下就好了。
既然上面说到了"去常量池里面拿一下就好了",那么把局部内部类、匿名内部类里面要用到的局部变量设定为static的也是可以的(不过static不可以修饰局部变量,可以放在方法外)
1、Java允许实现多个接口,但不允许继承多个类,使用成员内部类可以解决Java不允许继承多个类的问题。在一个类的内部写一个成员内部类,可以让这个成员内部类继承某个原有的类,这个成员内部类又可以直接访问其外部类中的所有属性与方法,是不是相当于多继承了呢
2、成员内部类可以直接访问其外部类的private属性,而新起一个外部类则必须通过setter/getter访问类的private属性
3、有些类明明知道程序中除了某个固定地方都不会再有别的地方用这个类了,为这个只用一次的类定义一个外部类显然没必要,所以可以定义一个局部内部类或者成员内部类,写一段代码用用就好了
4、内部类某种程度上来说有效地对外隐藏了自己,比如我们常用的开发工具Eclipse、MyEclipse,看代码一般用的都是Packge这个导航器,Package下只有.java文件,我们是看不到定义的内部类的.java文件的
5、使用内部类可以让类与类之间的逻辑上的联系更加紧密
一.静态内部类可以有静态成员,而非静态内部类则不能有静态成员。、
二.静态内部类的非静态成员可以访问外部类的静态变量,而不可访问外部类的非静态变量;
三.非静态内部类的非静态成员可以访问外部类的非静态变量。
定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例话,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。
public class SingletonEH {
/**
*是否 Lazy 初始化:否
*是否多线程安全:是
*实现难度:易
*描述:这种方式比较常用,但容易产生垃圾对象。
*优点:没有加锁,执行效率会提高。
*缺点:类加载时就初始化,浪费内存。
*它基于 classloder 机制避免了多线程的同步问题,
* 不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,
* 在单例模式中大多数都是调用 getInstance 方法,
* 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,
* 这时候初始化 instance 显然没有达到 lazy loading 的效果。
*/
private static SingletonEH instance = new SingletonEH();
private SingletonEH (){}
public static SingletonEH getInstance() {
System.out.println("instance:"+instance);
System.out.println("加载饿汉式....");
return instance;
}
}
定义一个类,它的构造函数为private的,它有一个static的private的该类变量,只有当调用getInstance的时候,才回去初始化这个单例。
public class SingletonLH {
/**
*是否 Lazy 初始化:是
*是否多线程安全:否
*实现难度:易
*描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
*这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
*/
private static SingletonLH instance;
private SingletonLH (){}
public static SingletonLH getInstance() {
if (instance == null) {
instance = new SingletonLH();
}
return instance;
}
}