Как я обращаюсь к API Java 1.6 при ухудшении корректно против Java 1.5?

Давайте запустимся с retain и release; autorelease действительно просто особый случай, после того как Вы понимаете фундаментальные понятия.

В Какао, каждый объект отслеживает то, сколько раз на это ссылаются (а именно, NSObject, базовый класс реализует это). Путем вызова retain на объекте, Вы говорите этому, что хотите к его подсчету ссылок одним. Путем вызова release, Вы говорите объекту, что отпускаете его, и его подсчет ссылок постепенно уменьшается. Если, после вызова release, подсчет ссылок является теперь нулем, то память того объекта освобождена системой.

основной способ, которым это отличается от [1 110] и free, состоит в том, что любой данный объект не должен волноваться о других частях системного катастрофического отказа, потому что Вы освободили память, которую они использовали. Принятие всех манипулирует и сохраняет/выпускает согласно правилам, когда одна часть кода сохранит и затем выпускает объект, любая другая часть кода, также ссылающегося на объект, будет незатронута.

то, Что может иногда сбивать с толку, знает обстоятельства, при которых необходимо звонить retain и release. Мое общее эмпирическое правило - то, что, если я хочу держаться за объект в течение некоторого отрезка времени (если это - членская переменная в классе, например), затем я должен удостовериться, что подсчет ссылок объекта знает обо мне. Как описано выше, подсчет ссылок объекта увеличен путем вызова retain. Условно, это также увеличено (набор к 1, действительно), когда объект создается с "init" методом. В любом из этих случаев это - моя обязанность звонить release на объекте, когда я сделан с ним. Если я не сделаю, то будет утечка памяти.

Пример создания объекта:

NSString* s = [[NSString alloc] init];  // Ref count is 1
[s retain];                             // Ref count is 2 - silly
                                        //   to do this after init
[s release];                            // Ref count is back to 1
[s release];                            // Ref count is 0, object is freed

Теперь для [1 116]. Автовыпуск используется в качестве удобного (и иногда необходимый) способ сказать системе освобождать этот объект скоро. С точки зрения инфраструктуры, когда autorelease назван, текущий поток NSAutoreleasePool предупрежден вызова. NSAutoreleasePool теперь знает, что, после того как это получает возможность (после текущего повторения цикла событий), это может звонить release на объекте. С нашей точки зрения как программисты это заботится о вызове release для нас, таким образом, мы не имеем к (и на самом деле, мы не были должны).

то, Что важно для примечания, - то, что (снова, условно) все создание объекта методы класса возвращают автовыпущенный объект. Например, в следующем примере, переменная "s" имеет подсчет ссылок 1, но после того, как цикл событий завершается, это будет уничтожено.

NSString* s = [NSString stringWithString:@"Hello World"];

, Если бы Вы хотите зависнуть на ту строку, необходимо было бы звонить retain явно, и затем явно release она, когда Вы сделаны.

Считают следующее (очень изобретенным) битом кода, и Вы будете видеть ситуацию, где autorelease требуется:

- (NSString*)createHelloWorldString
{
    NSString* s = [[NSString alloc] initWithString:@"Hello World"];

    // Now what?  We want to return s, but we've upped its reference count.
    // The caller shouldn't be responsible for releasing it, since we're the
    // ones that created it.  If we call release, however, the reference 
    // count will hit zero and bad memory will be returned to the caller.  
    // The answer is to call autorelease before returning the string.  By 
    // explicitly calling autorelease, we pass the responsibility for
    // releasing the string on to the thread's NSAutoreleasePool, which will
    // happen at some later time.  The consequence is that the returned string 
    // will still be valid for the caller of this function.
    return [s autorelease];
}

я понимаю, что все это немного сбивает с толку - в какой-то момент, тем не менее, это нажмет. Вот несколько ссылок для получения Вас движение:

10
задан Simon Nickerson 14 August 2009 в 11:01
поделиться

6 ответов

Обычный способ сделать это - через отражение, т. Е. не обращайтесь напрямую к рассматриваемому классу, а вызывайте его программно. Это позволяет вам изящно перехватывать исключения, если рассматриваемый код не существует, и либо игнорировать его, либо пробовать что-то еще. Отражение выбрасывает ClassNotFoundException , что является хорошим нормальным исключением, а не NoClassDefFoundError , что немного страшнее.

В случае java.text.Normalizer ], это должно быть довольно просто, поскольку это всего лишь пара статических методов, и легко вызывать через отражение.

13
ответ дан 3 December 2019 в 15:52
поделиться

Я не возражаю, если код, работающий на 1.5, не выполняет нормализацию, но я не хочу, чтобы он выдавал NoClassDefFoundErrors или ClassNotFoundExceptions при запуске.

Если вы хотите избегайте отражения, вы действительно можете поймать эти ошибки.

Таким образом, вы можете скомпилировать блестящие новые классы с помощью компилятора Java6, и он все равно будет работать (например, «ничего не делать, но и не давать сбоев») на Java5 .

Вы также можете объединить два подхода и проверить, существует ли класс, используя отражение, и продолжает ли он вызывать его неотражающим образом. Это то, что делает решение Эндрю.

Если вам также нужно скомпилировать на Java5, тогда вам нужно полностью отреагировать.

3
ответ дан 3 December 2019 в 15:52
поделиться

У меня была такая же потребность, поскольку у нас есть код, который должен работать на всех версиях Java, начиная с Java 1.2, но некоторый код должен использовать преимущества более новых API, если они доступны.

После различных перестановок с использованием отражения для получения объектов Method и их динамического вызова я в целом остановился на подходе в стиле оболочки (хотя при некоторых обстоятельствах лучше просто сохранить отраженный метод как статический и вызывать его - это зависит).

Ниже приведен пример класса «Системная утилита», который предоставляет некоторые новые API для Java 5 при запуске более ранней версии - те же принципы действуют для Java 6 в более ранних JVM. В этом примере используется синглтон, но можно легко создать экземпляры нескольких объектов, если это необходимо базовому API.

Существует два класса:

  • SysUtil
  • SysUtil_J5

Последний используется, если исполняемая JVM это Java 5 или новее. В противном случае используются резервные методы, которые совместимы по контракту, из реализации по умолчанию в SysUtil, которая использует только API Java 4 или более ранние версии. Каждый класс компилируется с помощью компилятора конкретной версии, поэтому случайное использование API Java 5+ в классе Java 4 не допускается:

SysUtil (скомпилировано с помощью компилятора Java 4)

import java.io.*;
import java.util.*;

/**
 * Masks direct use of select system methods to allow transparent use of facilities only
 * available in Java 5+ JVM.
 *
 * Threading Design : [ ] Single Threaded  [x] Threadsafe  [ ] Immutable  [ ] Isolated
 */

public class SysUtil
extends Object
{

/** Package protected to allow subclass SysUtil_J5 to invoke it. */
SysUtil() {
    super();
    }

// *****************************************************************************
// INSTANCE METHODS - SUBCLASS OVERRIDE REQUIRED
// *****************************************************************************

/** Package protected to allow subclass SysUtil_J5 to override it. */
int availableProcessors() {
    return 1;
    }

/** Package protected to allow subclass SysUtil_J5 to override it. */
long milliTime() {
    return System.currentTimeMillis();
    }

/** Package protected to allow subclass SysUtil_J5 to override it. */
long nanoTime() {
    return (System.currentTimeMillis()*1000000L);
    }

// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************

static private final SysUtil            INSTANCE;
static {
    SysUtil                             instance=null;

    try                  { instance=(SysUtil)Class.forName("SysUtil_J5").newInstance(); } // can't use new SysUtil_J5() - compiler reports "class file has wrong version 49.0, should be 47.0"
    catch(Throwable thr) { instance=new SysUtil();                                                                    }
    INSTANCE=instance;
    }

// *****************************************************************************
// STATIC METHODS
// *****************************************************************************

/**
 * Returns the number of processors available to the Java virtual machine.
 * <p>
 * This value may change during a particular invocation of the virtual machine. Applications that are sensitive to the
 * number of available processors should therefore occasionally poll this property and adjust their resource usage
 * appropriately.
 */
static public int getAvailableProcessors() {
    return INSTANCE.availableProcessors();
    }

/**
 * Returns the current time in milliseconds.
 * <p>
 * Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the
 * underlying operating system and may be larger. For example, many operating systems measure time in units of tens of
 * milliseconds.
 * <p>
 * See the description of the class Date for a discussion of slight discrepancies that may arise between "computer time"
 * and coordinated universal time (UTC).
 * <p>
 * @return         The difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
 */
static public long getMilliTime() {
    return INSTANCE.milliTime();
    }

/**
 * Returns the current value of the most precise available system timer, in nanoseconds.
 * <p>
 * This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock
 * time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values
 * may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees
 * are made about how frequently values change. Differences in successive calls that span greater than approximately 292
 * years (263 nanoseconds) will not accurately compute elapsed time due to numerical overflow.
 * <p>
 * For example, to measure how long some code takes to execute:
 * <p><pre>
 *    long startTime = SysUtil.getNanoTime();
 *    // ... the code being measured ...
 *    long estimatedTime = SysUtil.getNanoTime() - startTime;
 * </pre>
 * <p>
 * @return          The current value of the system timer, in nanoseconds.
 */
static public long getNanoTime() {
    return INSTANCE.nanoTime();
    }

} // END PUBLIC CLASS

SysUtil_J5 (скомпилировано с помощью Java 5)

import java.util.*;

class SysUtil_J5
extends SysUtil
{

private final Runtime                   runtime;

SysUtil_J5() {
    super();

    runtime=Runtime.getRuntime();
    }

// *****************************************************************************
// INSTANCE METHODS
// *****************************************************************************

int availableProcessors() {
    return runtime.availableProcessors();
    }

long milliTime() {
    return System.currentTimeMillis();
    }

long nanoTime() {
    return System.nanoTime();
    }

} // END PUBLIC CLASS
1
ответ дан 3 December 2019 в 15:52
поделиться
public interface NfcNormalizer
{
  public String normalize(String str);
}

public class IdentityNfcNormalizer implements NfcNormalizer
{
  public String normalize(String str)
  {
    return str;
  }
}

public class JDK16NfcNormalizer implements NfcNormalizer
{
  public String normalize(String str)
  {
    return Normalizer.normalize(str, Normalizer.Form.NFC);
  }
}

В коде вашего клиента:

NfcNormalizer normalizer;
try
{
  normalizer = Class.forName("JDK16NfcNormalizer").newInstance();
}
catch(Exception e)
{
  normalizer = new IdentityNfcNormalizer();
}
9
ответ дан 3 December 2019 в 15:52
поделиться

Проверить / использовать / изменить класс info.olteanu.utils.TextNormalizer в проекте Phramer ( http://sourceforge.net/projects/phramer/ ], www.phramer.org) - код лицензирован BSD.

Этот код может быть скомпилирован на Java 5 и работает как на Java 5, так и на Java 6 (или будущих версиях Java). Кроме того, его можно скомпилировать на Java 6 и запустить на Java 5 (если он был скомпилирован с правильным "-target" для совместимости с байт-кодом) или Java 6 или любой другой будущей версии.

IMHO, это полностью решает вашу проблему - вы можете компилировать на любой платформе Java 5+, и вы можете получить желаемую функциональность (нормализацию) на любой платформе Java 5+ (*)

(*) Решение SUN Java 5 для нормализации, скорее всего, не присутствует во всех реализациях Java 5,

1
ответ дан 3 December 2019 в 15:52
поделиться
    String str = "éèà";
    try {
        Class c = Class.forName("java.text.Normalizer");
        Class f = Class.forName("java.text.Normalizer$Form");
        Field ff = f.getField("NFD");
        Method m = c.getDeclaredMethod("normalize", new Class[]{java.lang.CharSequence.class,f});
        temp = (String) m.invoke(null, new Object[]{str,ff.get(null)});
    } catch (Throwable e) {
        System.err.println("Unsupported Normalisation method (jvm <1.6)");
    }
    System.out.println(temp+" should produce [eea]");
0
ответ дан 3 December 2019 в 15:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: