基础知识的总结
数据类型:基本数据类型和引用数据类型
基本数据数据类型(boolean.byte.short.int.lang.float.double.char)
引用类型(类、接口、数组)
重载(overLoad)和重写(override)
重载满足要素:方法名相同、参数的类型和参数的个数不同,和方法返回值、修饰符等无关
重写满足要素:方法名相同、形参列表相同、返回值类型比父类返回值更小或相等、访问权限比父类方法更大或相等
java的标示符规则:
1.字母、数字、下划线、美元符号,并且不能以数字开头
2.标示符不能为java的关键字和保留字符(goto)
基本类型转换字符串的方法:
基本类型转换成字符串的的方法:
第一种:String.valueof(基本类型)
第二种:空字符串加上基本类型,得到基本类型字符串(这里是空字符串不是空格字符串)
第三种:调用对象的toString()
字符串转换成基本类型的两个方法:
1、调用基本类型封装类的paresexxx静态方法
2、用字符串构造基本类型,再调用封装对象的xxxValue方法
------------------------------------
Set set = hashMap.keySet();
//问题1:hashMap.keySet方法返回一个Set对象,Set是接口,
//接口可以有引用,并指向其子类对象。但是怎么可以有一个引用set指向自己的对象呢?
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
public class CollectionDemo {
public static void main(String[] args) {
Person p1 = new Person(21);
Person p2 = new Person(23);
Person p3 = new Person(21);
HashMap hashMap = new HashMap();
hashMap.put("zhangsan", p1);
hashMap.put("lisi", p2);
hashMap.put("wangwu", p3);
Set set = hashMap.keySet();
//问题1:hashMap.keySet方法返回一个Set对象,Set是接口,
//接口可以有引用,并指向其子类对象。但是怎么可以有一个引用set指向自己的对象呢?
Iterator i = set.iterator();
while(i.hasNext()){
String s = i.next();//这里提示错误,应该把s的类型改为person
//问题2:i.next方法应该返回一个String,这里为什么会报错?
解答:其实在java的hashMap中还有一个内部类,这个类就是keySet
你可以在你的代码中用 System.out.println(hashMap.keySet().getClass().getName())试试看,
返回的java.util.HashMap$KeySet,这就代表Set通过keySet方法获得的Set对象其实是hashMap的内部类实例。而对于注释部分的keySet,因为keySet其实只需要有一个就可以了,因为每个hashMap集合只可能有一种key队列,多了就浪费空间了,所以除了第一次会new一个新的对象,你再次调用,就把以前已经创建的keyset对象给你
//并提示应该把s的类型改为person?
System.out.println(i.next());//而这里直接打印出的又是person。
解释:②因为你没有加泛型限定,所以i.next返回的是Object类型的,必须要进行强转或者对迭代器进行类型限定,你这里就限定成String类型
}
}
}
Constructor[] constructors=Class.forName("java.lang.String").getConstructors();
---------------------------------------------------------------------------------
synchronized:在代码里,synchronized类似“面向对象”,修饰类、方法、对象
Lock:不作为修饰,类似“面向过程”,在方法中需要锁的时候lock,在结束的时候,unlock(一般在finally块里)
代码:
public void metho(){
synchronized(this){//旧锁,无须人工释放
System.out.println(1);
}
}
public void method2(){
Lock lock=new ReentrantLock();
lock.lock();//上锁
try{
System.out.println(2);
}finally{
lock.unlock();//解锁
}
synchronzied--对象加锁:
所有对象都自动含有单一的锁,jvm负责跟踪对象被加锁的次数。如果一个对象被锁,其记数变为0。在任务(线程)第一次给对象加锁的时候,记数变为1。每当这个相同的任务(线程)在此对象上获得锁时,记数会递增。只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。每当任务离开时,记数递减,当记数为0的时候,锁被完全释放。sychronized就是基于这个原理,同时synchronized考某个独享的单一锁技术的次数来判断是是否被锁,所以无需(也不能)人工干预锁的获取和释放。
}
Lock---基于栈中的框架,而不是对象级别:
lock不同于synchronized,它基于栈中的框架而不是某个具体对象,所以Lock只需在栈里设置锁的开始和结束(lock和unlock)的地方,就行了(人工必须注明),不需要关心框架大小对象的变化等等。这么做的好处是Lock能提供无条件的、可轮询的、定时、可中断的锁获取操作,相对于synchronized来说,synchronized的锁的获取和释放不在一个模块里,获取和释放的顺序必须相反,而Lock则可以在不同范围内获取释放,并且顺序无关。
------------------------------------------------------------------
TreeSet的排序方式有下面两种:
1:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
class Student implements Comparable//该接口强制让学生类具备比较性
{ Student()
{}
public int compareTo(Object obj)
{}
}
2:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。
这时就需要定义一个比较器类去实现Comparator,并重写compare方法。
class MyCompare implements Comparator //自定义比较器,使集合具备比较性
{ public int compare(Object o1,Object o2)
{}
}
在定义集合时,需要根据实际情况选择排序方式:
1、TreeSet ts =new TreeSet(); //此时的排序方式为第一种,即元素的自然排序方式。
2、TreeSet ts =new TreeSet(new MyCompare()); //此时的排序方式为第二种,即集合自身具备比较性。
---------------------------------------------------------------------------------------------
Set:无序,不可以重复元素
|---Hashset:数据结构式哈希表。线程是非同步的。
包成元素唯一性的原理:判断元素的hashCode值是否相同
如果相同,还会继续判断元素的equals方法,是否为true。
采用hash表
|---Treeset:可以对Set集合中的元素进行排序
底层数据结构式二叉树
保证元素唯一性的依据:
compareTo方法 return ();和hash表没关系
TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法
这种方式也成为元素的自然排序,或者叫做默认排序。
注意:排序时,当主要条件相同时,一定判断一下次要条件。当对象很多时,耗时。
treeset采用二叉树形式保存数据!保存数据后查询的时候采用折半查询
TreeSet排序的第二种方式:
当元素自身不具备比较性时,或者具有的比较性不是不是所需要的。
这时就需要让集合自身具备比较性,定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数
在集合初始化时,就有了比较方式。
----------------------------------------------------------------------------------------------
解释是这样的,当你往集合中添加第一个元素的时候,(不管你重写不重写)集合都会自动调用hasCode方法,算出一个哈希值
当你再往集合中添加元素时。系统会再算出此元素的哈希值,并自动判断跟之前元素的哈希值是否相同。如果相同,就需要equals方法,来判断元素的属性是否都一样。
给你举个例子
元素要往哈希表结构的容器中存储,必须具备hashCode和equals方法。(Object已经提供了这两个方法。 对象创建在堆内存中就是因为有了hashCode方法.)
//覆写hashCode方法的原因。Object中的hashCode是本地(windows)方法,只算内存地址.
//不覆写会根据内存地址判断资料相同的人不是同一个人。
//满足不了人的姓名和年龄相同 既为同一个人的要求。所以要依据对象自身特别不同。
//覆写equals的原因:HashSet判断元素唯一的依据是自动调用equals方法。
//不覆写的话,如果hash值万一相同的话,就需要逐个比较元素的属性,而原来的equals满足不了这个要求
代码如下:
@Override
// 覆写hashCode方法的原因。Object中的hashCode是本地(windows)方法,只算内存地址.
// 不覆写会根据内存地址判断资料相同的人不是同一个人。
// 满足不了 人的姓名和年龄相同 既为同一个人的要求。所以要依据对象自身特别不同。
public int hashCode() {
final int prime = 31;
return name.hashCode() + age * prime;
// *prime的原因。防止姓名的哈希值是40,年龄是20 与姓名的哈希值是20,年龄是40 。而引起哈希值相同,多运行equals方法
}
@Override
// 覆写equals的原因:HashSet判断元素唯一的依据是自动调用equals方法。
// 不覆写的话,如果hash值万一相同的话,就需要逐个比较元素的属性,而原来的equals满足不了这个要求,
//如果主方法中添加的元素内容不是一模一样的,几乎不可能调用equals方法。
-----------------------------------------------------------------------------------------------
/首先,内部类其实就是一个子类对象
//其实内部类的出现,在一定意义上实现了多继承。因为内部类 可以有多个,分别继承别的类。外部类也可以用内部类里的方法了。
//然后,关于你的问题。子类如果想继承抽象内部类,就必须在这个类中定义一个带有外部类对象的构造方法,并在构造方法中调用外部类.super();
代码如下:
class Outer {
abstract class Inner {
abstract void show();
public void print() {
}
}
}
class Test extends Outer.Inner {// 如果不这么继承,必须导入Inner类的包。
Test(Outer out) {
out.super();
}
@Override
void show() {
}
}
两外一种解释:
class AbstractTest { //这里类修饰符可以使用abstract 修饰
static abstract class A{
/* A作为抽象类,那么static 必须保留,做为类静态成员变量。 A内部类,为外部类AbstractTest 的一个成员属性,随着对象的创建而加载,不能直接调用内部类,要调用只能new AbstractTest ().A。要想继承的话,只能把内部类改成静态内部类,static abstract class A {},此时对着类的加载而加载。*/
abstract void say();
}
void c(){
System.out.println("sss");
}
}
class B extends AbstractTest.A{
public static void main(String[] args){
}
@Override
void say() {
// TODO Auto-generated method stub
}
}
重点:非静态内部类,伴随着类的实例化开辟内存单元。 A抽象内部类,为外部类AbstractTest 的一个成员属性,随着对象的创建而加载,不能直接调用内部类,要调用只能new AbstractTest ().A。要想继承的话,只能把内部类改成静态内部类,static abstract class A {},此时对着类的加载而加载。
---------------------------------------------------------------------------------
--------- javac ----------
Main.java:11: 错误: 需要包含Outer.InnerAbs的封闭实例
class AA extends Outer.InnerAbs
^
1 个错误
为什么会产生这样的错误?
能不能修改这个错误,同时还能保证AA能够继承Outer.InnerAbs ?
-----------------------------
编译器的意思是:要创建Outer.InnerAbs的子类对象必须保留一个外部类的引用。
原理如下:
当创建一个子类时,子类构造函数总会调用父类的构造函数,因此在创建
非静态内部类的子类时,必须保证让子类构造函数可以调用非静态内部类
的构造函数,调用非静态内部类的构造函数时,必须存在一个外部类对象,
因为当调用非静态内部类的实例方法时,必须有一个非静态内部类实例,
而非静态内部类实例必须寄存在外部内实例里。
代码可以修改如下:
class Outer
{
int a=90;
public abstract class InnerAbs
{
int b=80;
abstract void inAbs();
}
}
class AA extends Outer.InnerAbs
{
//显式定义AA(非静态内部类子类)的构造函数
AA(Outer out)
{
out.super();
}
void inAbs()
{
System.out.println("AA……inAbs");
}
}
class Main
{
public static void main(String[] args)
{
Outer out = new Outer();
//非静态内部类子类的创建
AA aa = new AA(out);
aa.inAbs();
}
}