A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 曹睿翔 金牌黑马   /  2013-5-1 22:14  /  1692 人查看  /  7 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 曹睿翔 于 2013-5-1 23:03 编辑

static 是一个修饰符 用于修饰成员(成员变量,成员函数)
     静态内部类作为外部类的成员随着外部类的加载而加载

什么时候使用静态,什么时候定义静态函数?静态代码块的好处?
静态的函数调用的时候不需要new
static特点
       1、随着类的加载而加载
            也就是说:静态会随着类的消失而消失,说明他的生命周期最长
       2、优先于对象存在
       3、被所有对象所共享
       4、可以直接被类名调用

1.对象共享的数据,可以用静态。这样不用每个对象都开辟空间存放那个数据,可以节约内存。
2.如果方法没有用到对象的特有的东西,即没有使用到非静态变量还有非静态方法时,可以用静态方法。
3.静态代码块是类一加载就自动执行,相当于给类进行初始化。自己瞎想的,不知对不对,比如说一个程序,一打开就弹出个对话框,说欢迎你使用这个软件,像这东西,不是自己某些操作去调用它,你一运行程序他就自动执行了,所以这对话框代码就应该在静态代码块力。
------------------------------------------------------------------------------------------
静态代码块为什么不能被继承?
    静态代码块是来初始化类的 不是对象,是字节码对象的初始化
     因而不能被继承
   但是你实例化子类对象,会调用的


静态方法为什么能被定义为泛型?
静态方法是随类的加载而加载的,
泛型方法要直到被调用时才能确认要操作的参数类型,
这时将静态方法定义为泛型,岂不是要直到被调用时才能确认参数的数据类型,实在不懂,求解.
答:
加载和执行一样吗??
public static void ff(Object o) {
                System.out.println(o);
               
        }
在这个静态方法加载的时候就知道了o的类型?

     ff(new String());
    ff(new Integer());
你能说加载的时候就知道参数类型?
泛型类在创建的时候知道其泛型的类型。
而静态方法在调用的时候才动态指定

7 个回复

倒序浏览
本帖最后由 曹睿翔 于 2013-5-1 22:29 编辑


毕老师的视频上面关于静态内部类被外部其他类访问是这么说的。
1.在外部其他类中,如何直接访问static内部类的非静态成员呢?
new Outer.Inner().function();
  1. class Outer
  2. {
  3. int x =3;
  4. static class Inner {
  5. void function ()
  6. {
  7. System.out.println(a);
  8.                               }
  9. }
  10. }
复制代码
2.在外部其他类中,如何直接访问static 内部类的静态成员呢?
Outer.Inner.function();
  1. <span style="background-color: rgb(255, 255, 255); color: rgb(102, 102, 102); font-family: Monaco; font-size: 12px; line-height: 25.200000762939453px; ">class Outer</span>{
  2. int x =3;
  3. static class Inner{
  4. static                                void function (){
复制代码
这两个代码的加载过程是不是这样的:
new Outer.Inner().function();
1.因为Outer不是静态,Inner是静态的,需要加载Outer后才能调用Inner
2.调用Inner,创建Outer.Inner()的匿名对象[堆内存中
3.匿名对象调用方法
Outer.Inner.function();
因为Inner.class和它的function()都是静态的,编译的时候就进入了静态区
1.加载Outer类到内存
2.调用Inner
3.调用function();
问题2
关于();
对于方法,每次编程都需要带()
对于类,只新建类的对象的时候带();在调用类的时候就不用带()

静态同步函数,同步函数的锁问题  (别人的帖子,搜集得来)
     同步静态方法时会获取该类的Class对象,所以当一个线程进入同步的静态方法中时,线程监视器获取类本身的对象锁,其它线程不能进入这个类的任何静态同步方法。它不像实例方法,因为多个线程可以同时访问不同实例同步实例方法。
     并发线程中与共享变量有关的程序段称为临界区。学习毕老师的视频后,我们知道java中用关键字synchronized声明一段临界区,只要该为临界区加的是同一把锁就可以实现同步的,这里是我写过的代码,读者和写者问题,经典的同步问题。
  1. /**
  2. * 题目:用多线程同步思想实现对某个共享缓冲区的读写操作的设计,即一旦写入数据,马上读走。
  3. * 线程同步,说白了,强调的是先后次序,也就是说必须等我这边忙完了,你那边才开始。
  4. * */
  5. public class ReaderAndWrite {

  6.         public static void main(String[] args) {
  7.                
  8.                 Buffer buffer = new Buffer();
  9.                 String[] datas = {"张三","李四","王五","赵六"};
  10.                 new writer(buffer,datas).start();
  11.                 new Reader(buffer,datas).start();
  12.         }
  13. }

  14. class Buffer{
  15.         private String data;
  16.         private boolean isNull = true;//读写线程通信的信号量,true表示缓冲区为空,可写
  17.         public  void putData(String data){
  18.                 while (!isNull) {//等待isNull为true,即等待数据被读走
  19.                         try {
  20.                                 this.wait();
  21.                         } catch (InterruptedException e) {
  22.                                 e.printStackTrace();
  23.                         }
  24.                 }
  25.                 this.data = data;//此时isNull为true,即前一个数据已被取走
  26.                 isNull = false;//将信号量设为false,表示缓冲区不为空,用以通知读进程
  27.                 notify();//唤醒等待的读线程,以进行读取刚刚存入的数据
  28.         }
  29.         
  30.         public  String getData(){
  31.                 while (isNull) {//此时若isNull为true,即无数据,则等待isNull为false,即等待写入数据
  32.                         
  33.                         try {
  34.                                 this.wait();
  35.                         } catch (InterruptedException e) {
  36.                                 e.printStackTrace();
  37.                         }
  38.                 }
  39.                 isNull = true;//将信号量设为true,表示缓冲区为空,用以通知写进程
  40.                 notify();//唤醒等待的写线程,以进行写操作
  41.                 return data;//有数据则返回当前数据
  42.         }
  43. }

  44. class writer extends Thread{
  45.         private Buffer buffer;
  46.         private String[] datas;
  47.         public writer(Buffer buffer,String[] datas) {
  48.                 this.buffer = buffer;
  49.                 this.datas = datas;
  50.         }
  51.         public  void run(){        
  52.                 //很明显,涉及到缓冲区,则可以将表示缓冲区的共享变量设为锁
  53.                 synchronized (buffer) {
  54.                         for(int i = 0;i<datas.length;i++){
  55.                                 buffer.putData(datas[i]);
  56.                                 System.out.println("写入:"+datas[i]);        
  57.                         }
  58.                 }
  59.         }
  60. }

  61. class Reader extends Thread{
  62.         private Buffer buffer;
  63.         private String[] datas;
  64.         public Reader(Buffer buffer,String[] datas) {
  65.                 this.buffer = buffer;
  66.                 this.datas = datas;
  67.         }
  68.         public void run(){
  69.                 //使用与写操作相同的缓冲区,则设置同一把锁
  70.                 synchronized (buffer) {
  71.                         for(int i = 0;i<datas.length;i++){
  72.                                 System.out.println("读取:"+buffer.getData());        
  73.                         }
  74.                 }
  75.         }
  76. }
复制代码
回复 使用道具 举报
本帖最后由 曹睿翔 于 2013-5-1 22:35 编辑

其他知识:
------------------------------------------------------------
javap  最常用的用途是用来快速的查看一个类可用的方法

javap的标准输出是公有变量和类的成员函数。

它能获取成员函数并不是让你查看函数的具体封装。
就像你获取到的主函数 也同样没有大括号一样。。。。
你可以用javap -c 类名  获取到更多信息。
默认构造函数和自己写上的没区别,没写构造函数jvm会自动添加为demo(){},你用javap 查看默认构造函数没有{} 应该是虚拟机在编译时候会自动加上方法体也就是{}
------------------------------------------------
序列化是将对象状态转换为可保持或传输的格式的过程,它也是RMI用来在不同JVM之间传递对象的机制,或者通过方法的参数或者作为一个方法调用的返回值。但有三个例外序列化不需要读或者写入到流:
1. 序列化会忽略静态字段,因为他们不属于对象的任何状态
2. 基类的字段只有基类本身是序列化的时候才能被序列化。
3. 瞬间字段(Transient fields)
对象序列化包括如下步骤:
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。
对象反序列化的步骤如下:
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。
回复 使用道具 举报
这个帖子总结的好。  我要出去晃荡了,等我回来再审查审查。。
回复 使用道具 举报
曹睿翔 来自手机 金牌黑马 2013-5-2 11:49:18
报纸
黑马伍哲沂 发表于 2013-5-2 11:44
这个帖子总结的好。  我要出去晃荡了,等我回来再审查审查。。

好好审查,帮我加注释,你的理解
第二贴还有几个知识点需要整理,你也帮忙整理吧
回复 使用道具 举报
版主 辛苦啦!!!
回复 使用道具 举报
曹睿翔 发表于 2013-5-2 11:49
好好审查,帮我加注释,你的理解
第二贴还有几个知识点需要整理,你也帮忙整理吧 ...

整理就谈不上了。  后面还有些知识点,觉得我还没接触。  原本以为我会碰到问题,刚回来一看。发现又没什么了。  可能是一时想不起来了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马