黑马程序员java笔记之零-----基础知识

基础知识的总结
数据类型:基本数据类型和引用数据类型
基本数据数据类型(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();
      }
}

你可能感兴趣的:(java)