天天看点

黑马程序员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();

                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();

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();

      //显式定义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();