Java中各个重要定义
继承
final
1. 数据
声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。
- 对于基本类型,final 使数值不变;
- 对于引用类型,final 使引用不变,也就不能引用其它对象,但是被引用的对象本身是可以修改的。
final int x = 1; x = 2; // cannot assign value to final variable 'x' final A y = new A(); y.a = 1;
2. 方法
声明方法不能被子类覆盖。
3. 类
声明类不允许被继承。
重载(overload)和重写(override)
方法重写的前提: 必须要存在继承的关系。
方法的重写: 子父类出了同名的函数,这个我们就称作为方法的重写。
什么是时候要使用方法的重写:父类的功能无法满足子类的需求时。
重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。
3、重写的方法,子类的返回值类型必须要小于或者 等于父类的返回值类型; (比如说父类某方法返回类似是Object,而子类重写的方法必须是Object或者Object的子类,如可以是String)。
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法(此时也可能叫重载?),并没有对其进行重写;
6、静态方法不能被重写为非静态的方法(会编译出错);
7、父类方法被final时,无论该方法被public、protected及默认所修饰,子类均不能重写该方法。
方法的重载:在一个类中 存在两个或者两个 以上的同名函数,称作为方法重载。
重载的规则:
1、在使用重载时一般是只能相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,个数,或者是顺序;
也有特例是通过返回值区分,但是这种方法不是百分之百可以,例如
void f() {} int f() { return 1; } // 在int x =f()中,确实可以区分重载方法,但是直接使用f()则不行
所以我们只说区分方法重载只能是相同方法名,不同参数形式来实现。
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响。
super
代表父类对应的对象,所以用super访问在子类中无法直接使用的父类成员和方法,不仅仅是用来调用父类的构造函数
多态
概念:向上转型和目的是,和向下转型和目的
前期绑定(面向过程只有前期绑定)和后期绑定(动态绑定,运行时绑定)
以下不具有多态性:
1.子类覆盖父类的private方法
2.子类和父类具有相同名字的成员变量(具有名字的域),某个域的访问是在编译期进行,而任何域访问操作都是将由编译器解析,此时子类和父类相同名字的域实质上是两个不同的储存空间,所以此时子类对象转型为父类引用时候不是多态性(实际上很少发现,因为通常父类的成员都是private,只能通过调用方法来访问)
3.某个父类方法是静态的,不具有多态性、
构造器和多态:构造器不具备多态性,因为实际上是static方法,此声明是隐式的
链接:https://www.nowcoder.com/questionTerminal/3910188b1259470a9bb7109885ed48c8 来源:牛客网 public class Test { public static Test t1 = new Test(); { System.out.println("A"); } static { System.out.println("B"); } public static void main(String[] args) { Test t2 = new Test(); } }
此时输出 ABA,为什么不是BAA呢,因为静态成员变量和静态代码块的优先级是相同的,而构造代码块在创建对象时被调用,每次创建对象都会被调用,所以,先定义的先执行,如果把静态代码块放在静态成员前面输出就是BAA。
自动拆装箱
出处:https://www.nowcoder.com/questionTerminal/643b145a860f457d8a150869e1a17eba
自动拆装箱JDK需在1.5上
1、基本型和基本型封装型进行“==”运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer(0)会自动拆箱为int类型再进行比较,显然返回true;
2、两个Integer类型进行“==”比较,如果其值在-128至127,那么返回true,否则返回false,
这跟Integer.valueOf()的缓冲对象有关,当然如果此时是new的一个对象如:Integer a=new Integer(1)和Integer b=new Integer(1),a==b返回的是false,因为堆中指向不同的地址值。
3、两个基本型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true
4、基本型封装类型调用equals(),但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,再进行3中的比较。
int a=257; Integer b=257; Integer c=257; Integer b2=57; Integer c2=57; System.out.println(a==b);//true //System.out.println(a.equals(b)); 编译出错,基本型不能调用equals() System.out.println(b.equals(257.0));//false,先257.0进行封装,再进行3的比较 System.out.println(b==c);//false System.out.println(b2==c2);//true
char < short < int < float < double 不同类型运算结果类型向右边靠齐。
在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类:
vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
statck:堆栈类,先进后出
hashtable:就比hashmap多了个线程安全
enumeration:枚举,相当于迭代器
除了这些之外,其他的都是非线程安全的类和接口。
(当然除了集合框架别的也有线程安全的比如Stringbuffer,Properties)
如何去判断一个类是否是线程安全的?
java中的线程安全是什么:
就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问
什么叫线程安全:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
看过vector源码的同学就会知道他的许多操作都是加了synchronized修饰的比如他的添加元素。(不知道synchronized是什么意思的自行百度!)
public synchronized void addElement(E obj) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj; }
而HashMap的所有操作都没有加synchronized修饰 ,不如他的put源码
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for(Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash &&((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
再看看ArrayList的add方法的源码
public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
再看StringBuffer的append源码,他是有synchronized修饰的
public synchronized StringBuffer append(String str) { super.append(str); return this; }
最后是Properties的setProperty方法,他是有synchronized修饰的
public synchronized Object setProperty(String key, String value) { return put(key, value); }
由此就可以判断出谁是线程安全的了。
内联函数:https://www.nowcoder.com/questionTerminal/72dd83394d564bf8917c2eb146b80cf5
static final和final的区别
多态:静态分派,动态分派
https://blog.csdn.net/u010355144/article/details/45459895
https://blog.csdn.net/imooc_000000/article/details/80310467