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

  • 相关阅读:
    neutron外网介绍
    oracle时间转换问题汇总
    redhat72普通用户计划任务实现守护进程
    Rabbitmq消息持久化
    rabbitmq消息流转分析
    Rabbitmq基本概念
    protobuf传文件存入oracle
    X32指令自动委托
    IT系统上线事宜
    可转债业务玩法
  • 原文地址:https://www.cnblogs.com/lixiaolun/p/2832764.html
Copyright © 2020-2023  润新知